diff options
1215 files changed, 35959 insertions, 14524 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/boot/preloaded-classes b/boot/preloaded-classes index a696e03d5bdf..afd9984cb124 100644 --- a/boot/preloaded-classes +++ b/boot/preloaded-classes @@ -6469,6 +6469,7 @@ android.os.connectivity.WifiActivityEnergyInfo$1 android.os.connectivity.WifiActivityEnergyInfo android.os.connectivity.WifiBatteryStats$1 android.os.connectivity.WifiBatteryStats +android.os.flagging.AconfigPackage android.os.health.HealthKeys$Constant android.os.health.HealthKeys$Constants android.os.health.HealthKeys$SortedIntArray diff --git a/config/preloaded-classes b/config/preloaded-classes index ed402767ee64..343de0bf3b98 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -6473,6 +6473,7 @@ android.os.connectivity.WifiActivityEnergyInfo$1 android.os.connectivity.WifiActivityEnergyInfo android.os.connectivity.WifiBatteryStats$1 android.os.connectivity.WifiBatteryStats +android.os.flagging.AconfigPackage android.os.health.HealthKeys$Constant android.os.health.HealthKeys$Constants android.os.health.HealthKeys$SortedIntArray diff --git a/core/api/current.txt b/core/api/current.txt index 70e54d400d2f..3821b8a5c307 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6482,6 +6482,7 @@ package android.app { method public String getSortKey(); method public long getTimeoutAfter(); method public boolean hasImage(); + method @FlaggedApi("android.app.api_rich_ongoing") public boolean hasPromotableCharacteristics(); method public void writeToParcel(android.os.Parcel, int); field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT; field public static final int BADGE_ICON_LARGE = 2; // 0x2 @@ -27169,6 +27170,15 @@ package android.media.projection { package android.media.quality { + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ActiveProcessingPicture implements android.os.Parcelable { + ctor public ActiveProcessingPicture(int, @NonNull String); + method public int describeContents(); + method public int getId(); + method @NonNull public String getProfileId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.ActiveProcessingPicture> CREATOR; + } + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class AmbientBacklightEvent implements android.os.Parcelable { ctor public AmbientBacklightEvent(int, @Nullable android.media.quality.AmbientBacklightMetadata); method public int describeContents(); @@ -27255,13 +27265,14 @@ package android.media.quality { } @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method public void addActiveProcessingPictureListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method public void createPictureProfile(@NonNull android.media.quality.PictureProfile); method public void createSoundProfile(@NonNull android.media.quality.SoundProfile); - method @NonNull public java.util.List<android.media.quality.PictureProfile> getAvailablePictureProfiles(); - method @NonNull public java.util.List<android.media.quality.SoundProfile> getAvailableSoundProfiles(); + method @NonNull public java.util.List<android.media.quality.PictureProfile> getAvailablePictureProfiles(boolean); + method @NonNull public java.util.List<android.media.quality.SoundProfile> getAvailableSoundProfiles(boolean); method @NonNull public java.util.List<android.media.quality.ParamCapability> getParamCapabilities(@NonNull java.util.List<java.lang.String>); - method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String); - method @Nullable public android.media.quality.SoundProfile getSoundProfile(int, @NonNull String); + method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String, boolean); + method @Nullable public android.media.quality.SoundProfile getSoundProfile(int, @NonNull String, boolean); method public boolean isAmbientBacklightEnabled(); method public boolean isAutoPictureQualityEnabled(); method public boolean isAutoSoundQualityEnabled(); @@ -27269,6 +27280,7 @@ package android.media.quality { method public void registerAmbientBacklightCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.AmbientBacklightCallback); method public void registerPictureProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.PictureProfileCallback); method public void registerSoundProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.SoundProfileCallback); + method public void removeActiveProcessingPictureListener(@NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method public void removePictureProfile(@NonNull String); method public void removeSoundProfile(@NonNull String); method public void setAmbientBacklightEnabled(boolean); @@ -27280,6 +27292,10 @@ package android.media.quality { method public void updateSoundProfile(@NonNull String, @NonNull android.media.quality.SoundProfile); } + public static interface MediaQualityManager.ActiveProcessingPictureListener { + method public void onActiveProcessingPicturesChanged(@NonNull java.util.List<android.media.quality.ActiveProcessingPicture>); + } + public abstract static class MediaQualityManager.AmbientBacklightCallback { ctor public MediaQualityManager.AmbientBacklightCallback(); method public void onAmbientBacklightEvent(@NonNull android.media.quality.AmbientBacklightEvent); @@ -27287,7 +27303,7 @@ package android.media.quality { public abstract static class MediaQualityManager.PictureProfileCallback { ctor public MediaQualityManager.PictureProfileCallback(); - method public void onError(int); + method public void onError(@Nullable String, int); method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>); method public void onPictureProfileAdded(@NonNull String, @NonNull android.media.quality.PictureProfile); method public void onPictureProfileRemoved(@NonNull String, @NonNull android.media.quality.PictureProfile); @@ -27296,7 +27312,7 @@ package android.media.quality { public abstract static class MediaQualityManager.SoundProfileCallback { ctor public MediaQualityManager.SoundProfileCallback(); - method public void onError(int); + method public void onError(@Nullable String, int); method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>); method public void onSoundProfileAdded(@NonNull String, @NonNull android.media.quality.SoundProfile); method public void onSoundProfileRemoved(@NonNull String, @NonNull android.media.quality.SoundProfile); @@ -29940,7 +29956,7 @@ package android.net.http { public class X509TrustManagerExtensions { ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException; method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException; - method @FlaggedApi("android.net.platform.flags.x509_extensions_certificate_transparency") @NonNull public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(@NonNull java.security.cert.X509Certificate[], @Nullable byte[], @Nullable byte[], @NonNull String, @NonNull String) throws java.security.cert.CertificateException; + method @FlaggedApi("android.security.certificate_transparency_configuration") @NonNull public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(@NonNull java.security.cert.X509Certificate[], @Nullable byte[], @Nullable byte[], @NonNull String, @NonNull String) throws java.security.cert.CertificateException; method public boolean isSameTrustConfiguration(String, String); method public boolean isUserAddedCertificate(java.security.cert.X509Certificate); } @@ -34749,7 +34765,10 @@ 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 poll(); method public void recycle(android.os.Message); method public void release(); } @@ -41029,7 +41048,7 @@ package android.service.autofill { field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6 - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDMAN = 4; // 0x4 + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDENTIAL_MANAGER = 4; // 0x4 field public static final int UI_TYPE_DIALOG = 3; // 0x3 field public static final int UI_TYPE_INLINE = 2; // 0x2 field public static final int UI_TYPE_MENU = 1; // 0x1 @@ -44869,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"; @@ -44900,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"; @@ -45051,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"; @@ -45084,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"; @@ -45094,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"; @@ -45530,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 { @@ -45628,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 { @@ -47211,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(); @@ -47361,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 @@ -47384,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"; @@ -47427,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 @@ -47448,12 +47467,12 @@ package android.telephony { 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 @@ -47467,7 +47486,7 @@ package android.telephony { 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 @@ -55231,8 +55250,8 @@ package android.view { method public abstract void setTransformation(android.graphics.Matrix); method public abstract void setVisibility(int); method public abstract void setWebDomain(@Nullable String); - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; - field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.extra.VIRTUAL_STRUCTURE_TYPE"; + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; } public abstract static class ViewStructure.HtmlInfo { @@ -58345,6 +58364,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; @@ -58354,6 +58374,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/lint-baseline.txt b/core/api/lint-baseline.txt index ad5bd31828e0..e71dffaf152d 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -1,10 +1,4 @@ // Baseline format: 1.0 -ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_TYPE: - Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` -ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: - Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` - - BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: @@ -1191,10 +1185,6 @@ UnflaggedApi: android.R.dimen#system_corner_radius_xlarge: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xlarge UnflaggedApi: android.R.dimen#system_corner_radius_xsmall: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xsmall -UnflaggedApi: android.R.integer#status_bar_notification_info_maxnum: - Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.integer.status_bar_notification_info_maxnum -UnflaggedApi: android.R.string#status_bar_notification_info_overflow: - Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.string.status_bar_notification_info_overflow UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR: New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID: diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 92d1791ab681..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"; @@ -328,6 +330,7 @@ package android { field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES"; field public static final String READ_SAFETY_CENTER_STATUS = "android.permission.READ_SAFETY_CENTER_STATUS"; field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES"; + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final String READ_SUBSCRIPTION_PLANS = "android.permission.READ_SUBSCRIPTION_PLANS"; field @FlaggedApi("android.app.system_terms_of_address_enabled") public static final String READ_SYSTEM_GRAMMATICAL_GENDER = "android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"; field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO"; field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; @@ -7986,12 +7989,13 @@ package android.media.musicrecognition { package android.media.quality { @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method public void addGlobalActiveProcessingPictureListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.ActiveProcessingPictureListener); method @NonNull public java.util.List<java.lang.String> getPictureProfileAllowList(); method @NonNull public java.util.List<java.lang.String> getPictureProfilePackageNames(); - method @NonNull public java.util.List<android.media.quality.PictureProfile> getPictureProfilesByPackage(@NonNull String); + method @NonNull public java.util.List<android.media.quality.PictureProfile> getPictureProfilesByPackage(@NonNull String, boolean); method @NonNull public java.util.List<java.lang.String> getSoundProfileAllowList(); method @NonNull public java.util.List<java.lang.String> getSoundProfilePackageNames(); - method @NonNull public java.util.List<android.media.quality.SoundProfile> getSoundProfilesByPackage(@NonNull String); + method @NonNull public java.util.List<android.media.quality.SoundProfile> getSoundProfilesByPackage(@NonNull String, boolean); method public void setAutoPictureQualityEnabled(boolean); method public void setAutoSoundQualityEnabled(boolean); method public boolean setDefaultPictureProfile(@Nullable String); @@ -12709,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; @@ -14628,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 @@ -15009,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 { @@ -15096,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"; } @@ -15107,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 { @@ -15525,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 @@ -16068,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); @@ -16165,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>); @@ -16174,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); @@ -16239,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 @@ -16458,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 } } @@ -17800,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 @@ -19134,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/api/test-current.txt b/core/api/test-current.txt index 6230a59a62c0..8594caee32c5 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1402,9 +1402,9 @@ package android.credentials.selection { method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.selection.Entry); } - @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class IntentFactory { - method @NonNull public static android.content.Intent createCancelUiIntent(@NonNull android.content.Context, @NonNull android.os.IBinder, boolean, @NonNull String); - method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.content.Context, @NonNull android.credentials.selection.RequestInfo, @NonNull java.util.ArrayList<android.credentials.selection.ProviderData>, @NonNull java.util.ArrayList<android.credentials.selection.DisabledProviderData>, @NonNull android.os.ResultReceiver); + @FlaggedApi("android.credentials.flags.propagate_user_context_for_intent_creation") public class IntentFactory { + method @NonNull public static android.content.Intent createCancelUiIntent(@NonNull android.content.Context, @NonNull android.os.IBinder, boolean, @NonNull String, int); + method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.content.Context, @NonNull android.credentials.selection.RequestInfo, @NonNull java.util.ArrayList<android.credentials.selection.ProviderData>, @NonNull java.util.ArrayList<android.credentials.selection.DisabledProviderData>, @NonNull android.os.ResultReceiver, int); } @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public abstract class ProviderData implements android.os.Parcelable { diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 9140bdf4fba7..349b4edffc32 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -1,10 +1,4 @@ // Baseline format: 1.0 -ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_TYPE: - Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` -ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: - Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` - - BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer): Methods must not throw unchecked exceptions 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/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index eccb6ffb281c..abdfb53537f8 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -44,6 +44,8 @@ import android.os.PowerExemptionManager.ReasonCode; import android.os.PowerExemptionManager.TempAllowListType; import android.os.TransactionTooLargeException; import android.os.WorkSource; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; import android.util.ArraySet; import android.util.Pair; @@ -1352,6 +1354,14 @@ public abstract class ActivityManagerInternal { String reason, int exitInfoReason); /** + * Queries the offset data for a given method on a process. + * @hide + */ + public abstract void getExecutableMethodFileOffsets(@NonNull String processName, + int pid, int uid, @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback callback); + + /** * Add a creator token for all embedded intents (stored as extra) of the given intent. * * @param intent The given intent diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 27661ce21656..48b74f2d0776 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -165,6 +165,10 @@ import android.os.TelephonyServiceManager; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.os.instrumentation.ExecutableMethodFileOffsets; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; +import android.os.instrumentation.MethodDescriptorParser; import android.permission.IPermissionManager; import android.provider.BlockedNumberContract; import android.provider.CalendarContract; @@ -2236,6 +2240,29 @@ public final class ActivityThread extends ClientTransactionHandler args.arg6 = uiTranslationSpec; sendMessage(H.UPDATE_UI_TRANSLATION_STATE, args); } + + @Override + public void getExecutableMethodFileOffsets( + @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback resultCallback) { + Method method = MethodDescriptorParser.parseMethodDescriptor( + getClass().getClassLoader(), methodDescriptor); + VMDebug.ExecutableMethodFileOffsets location = + VMDebug.getExecutableMethodFileOffsets(method); + try { + if (location == null) { + resultCallback.onResult(null); + return; + } + ExecutableMethodFileOffsets ret = new ExecutableMethodFileOffsets(); + ret.containerPath = location.getContainerPath(); + ret.containerOffset = location.getContainerOffset(); + ret.methodOffset = location.getMethodOffset(); + resultCallback.onResult(ret); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } private @NonNull SafeCancellationTransport createSafeCancellationTransport( @@ -3918,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 @@ -3932,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..1f627794a0f4 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,12 +208,14 @@ 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 // although we don't expect more than 1. sActionConfigMap.put(action, - new Config(32, IpcDataCache.MODULE_SYSTEM, sActionApiNameMap.get(action))); + new Config(32, IpcDataCache.MODULE_SYSTEM, + sActionApiNameMap.get(action)).cacheNulls(true)); } return sActionConfigMap.get(action); diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 06d01ecfcf06..063501bf82a2 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -46,6 +46,8 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteCallback; import android.os.SharedMemory; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; @@ -183,4 +185,6 @@ oneway interface IApplicationThread { void scheduleTimeoutService(IBinder token, int startId); void scheduleTimeoutServiceForType(IBinder token, int startId, int fgsType); void schedulePing(in RemoteCallback pong); + void getExecutableMethodFileOffsets(in MethodDescriptor methodDescriptor, + in IOffsetCallback resultCallback); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index a4d8a5cd4673..aa2ada5372af 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3221,7 +3221,6 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) public boolean containsCustomViews() { return contentView != null || bigContentView != null @@ -3235,7 +3234,6 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) public boolean hasTitle() { return extras != null && (!TextUtils.isEmpty(extras.getCharSequence(EXTRA_TITLE)) @@ -3245,7 +3243,7 @@ public class Notification implements Parcelable /** * @hide */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) public boolean hasPromotableStyle() { final Class<? extends Style> notificationStyle = getNotificationStyle(); @@ -3257,11 +3255,16 @@ public class Notification implements Parcelable } /** - * @hide + * Returns whether the notification has all the characteristics that make it eligible for + * {@link #FLAG_PROMOTED_ONGOING}. This method does not factor in other criteria such user + * preferences for the app or channel. If this returns true, it does not guarantee that the + * notification will be assigned FLAG_PROMOTED_ONGOING by the system, but if this returns false, + * it will not. */ - @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING) + @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) public boolean hasPromotableCharacteristics() { return isColorizedRequested() + && isOngoingEvent() && hasTitle() && !isGroupSummary() && !containsCustomViews() @@ -4158,6 +4161,13 @@ public class Notification implements Parcelable /** * @hide */ + public boolean isOngoingEvent() { + return (flags & FLAG_ONGOING_EVENT) != 0; + } + + /** + * @hide + */ public boolean hasCompletedProgress() { // not a progress notification; can't be complete if (!extras.containsKey(EXTRA_PROGRESS) @@ -6014,8 +6024,9 @@ public class Notification implements Parcelable /** * @param isHeader If the notification is a notification header * @return An instance of mColors after resolving the palette + * @hide */ - private Colors getColors(boolean isHeader) { + public Colors getColors(boolean isHeader) { mColors.resolvePalette(mContext, mN.color, !isHeader && mN.isColorized(), mInNightMode); return mColors; } @@ -14755,7 +14766,6 @@ public class Notification implements Parcelable * A utility which stores and calculates the palette of colors used to color notifications. * @hide */ - @VisibleForTesting public static class Colors { private int mPaletteIsForRawColor = COLOR_INVALID; private boolean mPaletteIsForColorized = false; @@ -14829,10 +14839,7 @@ public class Notification implements Parcelable if (isColorized) { if (rawColor == COLOR_DEFAULT) { - int[] attrs = {R.attr.materialColorSecondary}; - try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { - mBackgroundColor = getColor(ta, 0, Color.WHITE); - } + mBackgroundColor = ctx.getColor(R.color.materialColorSecondary); } else { mBackgroundColor = rawColor; } @@ -14864,30 +14871,25 @@ public class Notification implements Parcelable mRippleAlpha = 0x33; } else { int[] attrs = { - R.attr.materialColorSurfaceContainerHigh, - R.attr.materialColorOnSurface, - R.attr.materialColorOnSurfaceVariant, - R.attr.materialColorPrimary, - R.attr.materialColorSecondary, - R.attr.materialColorTertiary, - R.attr.materialColorOnTertiary, - R.attr.materialColorTertiaryFixedDim, - R.attr.materialColorOnTertiaryFixed, R.attr.colorError, R.attr.colorControlHighlight }; + + mBackgroundColor = ctx.getColor(R.color.materialColorSurfaceContainerHigh); + mPrimaryTextColor = ctx.getColor(R.color.materialColorOnSurface); + mSecondaryTextColor = ctx.getColor(R.color.materialColorOnSurfaceVariant); + mPrimaryAccentColor = ctx.getColor(R.color.materialColorPrimary); + mSecondaryAccentColor = ctx.getColor(R.color.materialColorSecondary); + mTertiaryAccentColor = ctx.getColor(R.color.materialColorTertiary); + mOnTertiaryAccentTextColor = ctx.getColor(R.color.materialColorOnTertiary); + mTertiaryFixedDimAccentColor = ctx.getColor( + R.color.materialColorTertiaryFixedDim); + mOnTertiaryFixedAccentTextColor = ctx.getColor( + R.color.materialColorOnTertiaryFixed); + try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) { - mBackgroundColor = getColor(ta, 0, nightMode ? Color.BLACK : Color.WHITE); - mPrimaryTextColor = getColor(ta, 1, COLOR_INVALID); - mSecondaryTextColor = getColor(ta, 2, COLOR_INVALID); - mPrimaryAccentColor = getColor(ta, 3, COLOR_INVALID); - mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID); - mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID); - mOnTertiaryAccentTextColor = getColor(ta, 6, COLOR_INVALID); - mTertiaryFixedDimAccentColor = getColor(ta, 7, COLOR_INVALID); - mOnTertiaryFixedAccentTextColor = getColor(ta, 8, COLOR_INVALID); - mErrorColor = getColor(ta, 9, COLOR_INVALID); - mRippleAlpha = Color.alpha(getColor(ta, 10, 0x33ffffff)); + mErrorColor = getColor(ta, 0, COLOR_INVALID); + mRippleAlpha = Color.alpha(getColor(ta, 1, 0x33ffffff)); } mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor, mBackgroundColor, nightMode); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 87c861912036..8ed66eb7e6c0 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -49,7 +49,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -61,15 +60,18 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.Adjustment; import android.service.notification.Condition; +import android.service.notification.RateEstimator; import android.service.notification.StatusBarNotification; import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; import android.util.Log; +import android.util.LruCache; import android.util.proto.ProtoOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.InstantSource; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -643,9 +645,17 @@ public class NotificationManager { */ public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500; + private static final float MAX_NOTIFICATION_ENQUEUE_RATE = 5f; + + private final Context mContext; private final Map<CallNotificationEventListener, CallNotificationEventCallbackStub> mCallNotificationEventCallbacks = new HashMap<>(); + private final InstantSource mClock; + private final RateEstimator mEnqueueRateEstimator = new RateEstimator(); + private final LruCache<String, Boolean> mEnqueuedNotificationKeys = new LruCache<>(10); + private final Object mEnqueueThrottleLock = new Object(); + @UnsupportedAppUsage private static INotificationManager sService; @@ -661,10 +671,17 @@ public class NotificationManager { return sService; } + /** @hide */ + protected INotificationManager service() { + return getService(); + } + + /** {@hide} */ @UnsupportedAppUsage - /*package*/ NotificationManager(Context context, Handler handler) + public NotificationManager(Context context, InstantSource clock) { mContext = context; + mClock = clock; } /** {@hide} */ @@ -736,7 +753,7 @@ public class NotificationManager { */ public void notifyAsPackage(@NonNull String targetPackage, @Nullable String tag, int id, @NonNull Notification notification) { - INotificationManager service = getService(); + INotificationManager service = service(); String sender = mContext.getPackageName(); try { @@ -752,13 +769,12 @@ public class NotificationManager { * @hide */ @UnsupportedAppUsage - public void notifyAsUser(String tag, int id, Notification notification, UserHandle user) + public void notifyAsUser(@Nullable String tag, int id, Notification notification, + UserHandle user) { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); - - if (notificationClassification() - && NotificationChannel.SYSTEM_RESERVED_IDS.contains(notification.getChannelId())) { + if (discardNotify(tag, id, notification)) { return; } @@ -771,6 +787,37 @@ public class NotificationManager { } } + /** + * Determines whether a {@link #notify} call should be skipped. If the notification is not + * skipped, updates tracking metadata to use in future decisions. + */ + private boolean discardNotify(@Nullable String tag, int id, Notification notification) { + if (notificationClassification() + && NotificationChannel.SYSTEM_RESERVED_IDS.contains(notification.getChannelId())) { + return true; + } + + if (Flags.nmBinderPerfThrottleNotify()) { + String key = toEnqueuedNotificationKey(tag, id); + long now = mClock.millis(); + synchronized (mEnqueueThrottleLock) { + if (mEnqueuedNotificationKeys.get(key) != null + && !notification.hasCompletedProgress() + && mEnqueueRateEstimator.getRate(now) > MAX_NOTIFICATION_ENQUEUE_RATE) { + return true; + } + + mEnqueueRateEstimator.update(now); + mEnqueuedNotificationKeys.put(key, Boolean.TRUE); + } + } + + return false; + } + private static String toEnqueuedNotificationKey(@Nullable String tag, int id) { + return tag + "," + id; + } + private Notification fixNotification(Notification notification) { String pkg = mContext.getPackageName(); // Fix the notification as best we can. @@ -852,7 +899,7 @@ public class NotificationManager { * @param id An identifier for this notification. */ public void cancelAsPackage(@NonNull String targetPackage, @Nullable String tag, int id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.cancelNotificationWithTag(targetPackage, mContext.getOpPackageName(), tag, id, mContext.getUser().getIdentifier()); @@ -865,9 +912,15 @@ public class NotificationManager { * @hide */ @UnsupportedAppUsage - public void cancelAsUser(String tag, int id, UserHandle user) + public void cancelAsUser(@Nullable String tag, int id, UserHandle user) { - INotificationManager service = getService(); + if (Flags.nmBinderPerfThrottleNotify()) { + synchronized (mEnqueueThrottleLock) { + mEnqueuedNotificationKeys.remove(toEnqueuedNotificationKey(tag, id)); + } + } + + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")"); try { @@ -884,7 +937,13 @@ public class NotificationManager { */ public void cancelAll() { - INotificationManager service = getService(); + if (Flags.nmBinderPerfThrottleNotify()) { + synchronized (mEnqueueThrottleLock) { + mEnqueuedNotificationKeys.evictAll(); + } + } + + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancelAll()"); try { @@ -907,7 +966,7 @@ public class NotificationManager { * @param delegate Package name of the app which can send notifications on your behalf. */ public void setNotificationDelegate(@Nullable String delegate) { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); if (localLOGV) Log.v(TAG, pkg + ": cancelAll()"); try { @@ -922,7 +981,7 @@ public class NotificationManager { * your behalf, if there currently is one. */ public @Nullable String getNotificationDelegate() { - INotificationManager service = getService(); + INotificationManager service = service(); String pkg = mContext.getPackageName(); try { return service.getNotificationDelegate(pkg); @@ -938,7 +997,7 @@ public class NotificationManager { * See {@link #setNotificationDelegate(String)}. */ public boolean canNotifyAsPackage(@NonNull String pkg) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canNotifyAsPackage(mContext.getPackageName(), pkg, mContext.getUserId()); } catch (RemoteException e) { @@ -956,7 +1015,7 @@ public class NotificationManager { * {@link android.provider.Settings#ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT}. */ public boolean canUseFullScreenIntent() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canUseFullScreenIntent(mContext.getAttributionSource()); } catch (RemoteException e) { @@ -974,7 +1033,7 @@ public class NotificationManager { */ @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) public boolean canPostPromotedNotifications() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.canBePromoted(mContext.getPackageName()); } catch (RemoteException e) { @@ -989,7 +1048,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.app.Flags.FLAG_API_RICH_ONGOING) public void setCanPostPromotedNotifications(@NonNull String pkg, int uid, boolean allowed) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setCanBePromoted(pkg, uid, allowed, true); } catch (RemoteException e) { @@ -1024,7 +1083,7 @@ public class NotificationManager { * @param groups The list of groups to create */ public void createNotificationChannelGroups(@NonNull List<NotificationChannelGroup> groups) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.createNotificationChannelGroups(mContext.getPackageName(), new ParceledListSlice(groups)); @@ -1067,7 +1126,7 @@ public class NotificationManager { * @param channels the list of channels to attempt to create. */ public void createNotificationChannels(@NonNull List<NotificationChannel> channels) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.createNotificationChannels(mContext.getPackageName(), new ParceledListSlice(channels)); @@ -1085,7 +1144,7 @@ public class NotificationManager { * package (see {@link Context#createPackageContext(String, int)}).</p> */ public NotificationChannel getNotificationChannel(String channelId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannel(mContext.getOpPackageName(), mContext.getUserId(), mContext.getPackageName(), channelId); @@ -1105,7 +1164,7 @@ public class NotificationManager { */ public @Nullable NotificationChannel getNotificationChannel(@NonNull String channelId, @NonNull String conversationId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getConversationNotificationChannel(mContext.getOpPackageName(), mContext.getUserId(), mContext.getPackageName(), channelId, true, @@ -1124,7 +1183,7 @@ public class NotificationManager { * {@link Context#createPackageContext(String, int)}).</p> */ public List<NotificationChannel> getNotificationChannels() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannels(mContext.getOpPackageName(), mContext.getPackageName(), mContext.getUserId()).getList(); @@ -1145,7 +1204,7 @@ public class NotificationManager { && NotificationChannel.SYSTEM_RESERVED_IDS.contains(channelId)) { return; } - INotificationManager service = getService(); + INotificationManager service = service(); try { service.deleteNotificationChannel(mContext.getPackageName(), channelId); } catch (RemoteException e) { @@ -1159,7 +1218,7 @@ public class NotificationManager { * The channel group must belong to your package, or null will be returned. */ public NotificationChannelGroup getNotificationChannelGroup(String channelGroupId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationChannelGroup(mContext.getPackageName(), channelGroupId); } catch (RemoteException e) { @@ -1171,7 +1230,7 @@ public class NotificationManager { * Returns all notification channel groups belonging to the calling app. */ public List<NotificationChannelGroup> getNotificationChannelGroups() { - INotificationManager service = getService(); + INotificationManager service = service(); try { final ParceledListSlice<NotificationChannelGroup> parceledList = service.getNotificationChannelGroups(mContext.getPackageName()); @@ -1189,7 +1248,7 @@ public class NotificationManager { * belong to it. */ public void deleteNotificationChannelGroup(String groupId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.deleteNotificationChannelGroup(mContext.getPackageName(), groupId); } catch (RemoteException e) { @@ -1203,7 +1262,7 @@ public class NotificationManager { @TestApi public void updateNotificationChannel(@NonNull String pkg, int uid, @NonNull NotificationChannel channel) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.updateNotificationChannelForPackage(pkg, uid, channel); } catch (RemoteException e) { @@ -1216,7 +1275,7 @@ public class NotificationManager { */ @TestApi public ComponentName getEffectsSuppressor() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEffectsSuppressor(); } catch (RemoteException e) { @@ -1228,7 +1287,7 @@ public class NotificationManager { * @hide */ public boolean matchesCallFilter(Bundle extras) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.matchesCallFilter(extras); } catch (RemoteException e) { @@ -1241,7 +1300,7 @@ public class NotificationManager { */ @TestApi public void cleanUpCallersAfter(long timeThreshold) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.cleanUpCallersAfter(timeThreshold); } catch (RemoteException e) { @@ -1253,7 +1312,7 @@ public class NotificationManager { * @hide */ public boolean isSystemConditionProviderEnabled(String path) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isSystemConditionProviderEnabled(path); } catch (RemoteException e) { @@ -1271,7 +1330,7 @@ public class NotificationManager { /** @hide */ public void setZenMode(int mode, Uri conditionId, String reason, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setZenMode(mode, conditionId, reason, fromUser); } catch (RemoteException e) { @@ -1284,7 +1343,7 @@ public class NotificationManager { * @hide */ public int getZenMode() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getZenMode(); } catch (RemoteException e) { @@ -1297,7 +1356,7 @@ public class NotificationManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public ZenModeConfig getZenModeConfig() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getZenModeConfig(); } catch (RemoteException e) { @@ -1315,7 +1374,7 @@ public class NotificationManager { * </p> */ public @NonNull NotificationManager.Policy getConsolidatedNotificationPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getConsolidatedNotificationPolicy(); } catch (RemoteException e) { @@ -1327,7 +1386,7 @@ public class NotificationManager { * @hide */ public int getRuleInstanceCount(ComponentName owner) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getRuleInstanceCount(owner); } catch (RemoteException e) { @@ -1364,7 +1423,7 @@ public class NotificationManager { * See {@link #isNotificationPolicyAccessGranted}. */ public Map<String, AutomaticZenRule> getAutomaticZenRules() { - INotificationManager service = getService(); + INotificationManager service = service(); try { if (Flags.modesApi()) { return service.getAutomaticZenRules(); @@ -1398,7 +1457,7 @@ public class NotificationManager { * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}. */ public AutomaticZenRule getAutomaticZenRule(String id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAutomaticZenRule(id); } catch (RemoteException e) { @@ -1426,7 +1485,7 @@ public class NotificationManager { @NonNull public String addAutomaticZenRule(@NonNull AutomaticZenRule automaticZenRule, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.addAutomaticZenRule(automaticZenRule, mContext.getPackageName(), fromUser); @@ -1461,7 +1520,7 @@ public class NotificationManager { @FlaggedApi(Flags.FLAG_MODES_API) public boolean updateAutomaticZenRule(@NonNull String id, @NonNull AutomaticZenRule automaticZenRule, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.updateAutomaticZenRule(id, automaticZenRule, fromUser); } catch (RemoteException e) { @@ -1481,7 +1540,7 @@ public class NotificationManager { @FlaggedApi(Flags.FLAG_MODES_API) @Condition.State public int getAutomaticZenRuleState(@NonNull String id) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAutomaticZenRuleState(id); } catch (RemoteException e) { @@ -1527,7 +1586,7 @@ public class NotificationManager { * @param condition The new state of this rule */ public void setAutomaticZenRuleState(@NonNull String id, @NonNull Condition condition) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setAutomaticZenRuleState(id, condition); } catch (RemoteException e) { @@ -1555,7 +1614,7 @@ public class NotificationManager { @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public boolean removeAutomaticZenRule(@NonNull String id, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.removeAutomaticZenRule(id, fromUser); } catch (RemoteException e) { @@ -1574,7 +1633,7 @@ public class NotificationManager { /** @hide */ public boolean removeAutomaticZenRules(String packageName, boolean fromUser) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.removeAutomaticZenRules(packageName, fromUser); } catch (RemoteException e) { @@ -1587,7 +1646,7 @@ public class NotificationManager { * package. */ public @Importance int getImportance() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getPackageImportance(mContext.getPackageName()); } catch (RemoteException e) { @@ -1602,7 +1661,7 @@ public class NotificationManager { if (Flags.nmBinderPerfPermissionCheck()) { return mContext.checkSelfPermission(POST_NOTIFICATIONS) == PERMISSION_GRANTED; } else { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areNotificationsEnabled(mContext.getPackageName()); } catch (RemoteException e) { @@ -1623,7 +1682,7 @@ public class NotificationManager { */ @Deprecated public boolean areBubblesAllowed() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areBubblesAllowed(mContext.getPackageName()); } catch (RemoteException e) { @@ -1638,7 +1697,7 @@ public class NotificationManager { * @see Notification.Builder#setBubbleMetadata(Notification.BubbleMetadata) */ public boolean areBubblesEnabled() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.areBubblesEnabled(mContext.getUser()); } catch (RemoteException e) { @@ -1665,7 +1724,7 @@ public class NotificationManager { * @return the users' bubble preference for the app. */ public @BubblePreference int getBubblePreference() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getBubblePreferenceForPackage(mContext.getPackageName(), Binder.getCallingUid()); @@ -1685,7 +1744,7 @@ public class NotificationManager { * @hide */ public void silenceNotificationSound() { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.silenceNotificationSound(); } catch (RemoteException e) { @@ -1701,7 +1760,7 @@ public class NotificationManager { * PersistableBundle, SuspendDialogInfo) suspended}. */ public boolean areNotificationsPaused() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isPackagePaused(mContext.getPackageName()); } catch (RemoteException e) { @@ -1724,7 +1783,7 @@ public class NotificationManager { * user grant or denial of this access. */ public boolean isNotificationPolicyAccessGranted() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationPolicyAccessGranted(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1745,7 +1804,7 @@ public class NotificationManager { * {@link android.provider.Settings#ACTION_NOTIFICATION_LISTENER_SETTINGS}. */ public boolean isNotificationListenerAccessGranted(ComponentName listener) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationListenerAccessGranted(listener); } catch (RemoteException e) { @@ -1769,7 +1828,7 @@ public class NotificationManager { */ @SystemApi public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationAssistantAccessGranted(assistant); } catch (RemoteException e) { @@ -1785,7 +1844,7 @@ public class NotificationManager { * listeners}. */ public boolean shouldHideSilentStatusBarIcons() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.shouldHideSilentStatusIcons(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1804,7 +1863,7 @@ public class NotificationManager { */ @SystemApi public @NonNull @Adjustment.Keys List<String> getAllowedAssistantAdjustments() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAllowedAssistantAdjustments(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1818,7 +1877,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void allowAssistantAdjustment(@NonNull String capability) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.allowAssistantAdjustment(capability); } catch (RemoteException e) { @@ -1832,7 +1891,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void disallowAssistantAdjustment(@NonNull String capability) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.disallowAssistantAdjustment(capability); } catch (RemoteException e) { @@ -1843,7 +1902,7 @@ public class NotificationManager { /** @hide */ @TestApi public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String pkg) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.isNotificationPolicyAccessGrantedForPackage(pkg); } catch (RemoteException e) { @@ -1857,7 +1916,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void setAssistantAdjustmentKeyTypeState(@Adjustment.Types int type, boolean enabled) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setAssistantAdjustmentKeyTypeState(type, enabled); } catch (RemoteException e) { @@ -1870,7 +1929,7 @@ public class NotificationManager { */ @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setTypeAdjustmentForPackageState(pkg, enabled); } catch (RemoteException e) { @@ -1882,7 +1941,7 @@ public class NotificationManager { * @hide */ public List<String> getEnabledNotificationListenerPackages() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEnabledNotificationListenerPackages(); } catch (RemoteException e) { @@ -1899,7 +1958,7 @@ public class NotificationManager { * {@link #setNotificationPolicy(Policy)}. */ public Policy getNotificationPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getNotificationPolicy(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -1929,7 +1988,7 @@ public class NotificationManager { /** @hide */ public void setNotificationPolicy(@NonNull Policy policy, boolean fromUser) { checkRequired("policy", policy); - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationPolicy(mContext.getOpPackageName(), policy, fromUser); } catch (RemoteException e) { @@ -1939,7 +1998,7 @@ public class NotificationManager { /** @hide */ public void setNotificationPolicyAccessGranted(String pkg, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationPolicyAccessGranted(pkg, granted); } catch (RemoteException e) { @@ -1959,7 +2018,7 @@ public class NotificationManager { @TestApi @FlaggedApi(Flags.FLAG_MODES_API) public @NonNull ZenPolicy getDefaultZenPolicy() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getDefaultZenPolicy(); } catch (RemoteException e) { @@ -1971,7 +2030,7 @@ public class NotificationManager { */ @FlaggedApi(Flags.FLAG_MODES_UI) public void setManualZenRuleDeviceEffects(@NonNull ZenDeviceEffects effects) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setManualZenRuleDeviceEffects(effects); } catch (RemoteException e) { @@ -2008,7 +2067,7 @@ public class NotificationManager { @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted( @NonNull ComponentName listener, boolean granted, boolean userSet) { - INotificationManager service = getService(); + INotificationManager service = service(); try { if (CompatChanges.isChangeEnabled(SET_LISTENER_ACCESS_GRANTED_IS_USER_AWARE)) { service.setNotificationListenerAccessGrantedForUser(listener, mContext.getUserId(), @@ -2024,7 +2083,7 @@ public class NotificationManager { /** @hide */ public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationListenerAccessGrantedForUser(listener, userId, granted, true); } catch (RemoteException e) { @@ -2045,7 +2104,7 @@ public class NotificationManager { @SystemApi public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant, boolean granted) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setNotificationAssistantAccessGranted(assistant, granted); } catch (RemoteException e) { @@ -2069,7 +2128,7 @@ public class NotificationManager { /** @hide */ public List<ComponentName> getEnabledNotificationListeners(int userId) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getEnabledNotificationListeners(userId); } catch (RemoteException e) { @@ -2080,7 +2139,7 @@ public class NotificationManager { /** @hide */ @SystemApi public @Nullable ComponentName getAllowedNotificationAssistant() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.getAllowedNotificationAssistant(); } catch (RemoteException e) { @@ -2100,16 +2159,13 @@ public class NotificationManager { @SuppressLint("UserHandle") public boolean hasEnabledNotificationListener(@NonNull String packageName, @NonNull UserHandle userHandle) { - INotificationManager service = getService(); + INotificationManager service = service(); try { return service.hasEnabledNotificationListener(packageName, userHandle.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - - private Context mContext; - private static void checkRequired(String name, Object value) { if (value == null) { throw new IllegalArgumentException(name + " is required"); @@ -2125,7 +2181,7 @@ public class NotificationManager { @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_TOAST_RATE_LIMITING) public void setToastRateLimitingEnabled(boolean enable) { - INotificationManager service = getService(); + INotificationManager service = service(); try { service.setToastRateLimitingEnabled(enable); } catch (RemoteException e) { @@ -2917,7 +2973,7 @@ public class NotificationManager { * @return An array of {@link StatusBarNotification}. */ public StatusBarNotification[] getActiveNotifications() { - final INotificationManager service = getService(); + final INotificationManager service = service(); final String pkg = mContext.getPackageName(); try { final ParceledListSlice<StatusBarNotification> parceledList @@ -2940,7 +2996,7 @@ public class NotificationManager { * globally. */ public final @InterruptionFilter int getCurrentInterruptionFilter() { - final INotificationManager service = getService(); + final INotificationManager service = service(); try { return zenModeToInterruptionFilter(service.getZenMode()); } catch (RemoteException e) { @@ -2972,7 +3028,7 @@ public class NotificationManager { /** @hide */ public final void setInterruptionFilter(@InterruptionFilter int interruptionFilter, boolean fromUser) { - final INotificationManager service = getService(); + final INotificationManager service = service(); try { service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter, fromUser); @@ -3130,7 +3186,7 @@ public class NotificationManager { checkRequired("userHandle", userHandle); checkRequired("executor", executor); checkRequired("listener", listener); - INotificationManager service = getService(); + INotificationManager service = service(); try { synchronized (mCallNotificationEventCallbacks) { CallNotificationEventCallbackStub callbackStub = @@ -3161,7 +3217,7 @@ public class NotificationManager { public void unregisterCallNotificationEventListener( @NonNull CallNotificationEventListener listener) { checkRequired("listener", listener); - INotificationManager service = getService(); + INotificationManager service = service(); try { synchronized (mCallNotificationEventCallbacks) { CallNotificationEventCallbackStub callbackStub = @@ -3184,7 +3240,7 @@ public class NotificationManager { @TestApi @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public @NonNull Set<String> getUnsupportedAdjustmentTypes() { - INotificationManager service = getService(); + INotificationManager service = service(); try { return new HashSet<>(service.getUnsupportedAdjustmentTypes()); } catch (RemoteException e) { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 248e0433232a..920b19cd8f78 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -289,6 +289,7 @@ import com.android.internal.os.IDropBoxManagerService; import com.android.internal.policy.PhoneLayoutInflater; import com.android.internal.util.Preconditions; +import java.time.InstantSource; import java.util.Map; import java.util.Objects; @@ -625,7 +626,7 @@ public final class SystemServiceRegistry { com.android.internal.R.style.Theme_Holo_Dialog, com.android.internal.R.style.Theme_DeviceDefault_Dialog, com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)), - ctx.mMainThread.getHandler()); + InstantSource.system()); }}); registerService(Context.PEOPLE_SERVICE, PeopleManager.class, 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/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index ed088fed41c2..a731e5085466 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -34,6 +34,7 @@ import android.os.ICancellationSignal; import android.os.OutcomeReceiver; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.SystemClock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -179,7 +180,8 @@ public final class AppFunctionManager { ExecuteAppFunctionAidlRequest aidlRequest = new ExecuteAppFunctionAidlRequest( - request, mContext.getUser(), mContext.getPackageName()); + request, mContext.getUser(), mContext.getPackageName(), + /* requestTime= */ SystemClock.elapsedRealtime()); try { ICancellationSignal cancellationTransport = diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java index e623fa10f474..707d1fc0473e 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java @@ -41,8 +41,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { ExecuteAppFunctionRequest.CREATOR.createFromParcel(in); UserHandle userHandle = UserHandle.CREATOR.createFromParcel(in); String callingPackage = in.readString8(); + long requestTime = in.readLong(); return new ExecuteAppFunctionAidlRequest( - clientRequest, userHandle, callingPackage); + clientRequest, userHandle, callingPackage, requestTime); } @Override @@ -60,11 +61,15 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { /** The package name of the app that is requesting to execute the app function. */ private final String mCallingPackage; - public ExecuteAppFunctionAidlRequest( - ExecuteAppFunctionRequest clientRequest, UserHandle userHandle, String callingPackage) { + /** The time of calling executeAppFunction(). */ + private final long mRequestTime; + + public ExecuteAppFunctionAidlRequest(ExecuteAppFunctionRequest clientRequest, + UserHandle userHandle, String callingPackage, long requestTime) { this.mClientRequest = Objects.requireNonNull(clientRequest); this.mUserHandle = Objects.requireNonNull(userHandle); this.mCallingPackage = Objects.requireNonNull(callingPackage); + this.mRequestTime = requestTime; } @Override @@ -77,6 +82,7 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { mClientRequest.writeToParcel(dest, flags); mUserHandle.writeToParcel(dest, flags); dest.writeString8(mCallingPackage); + dest.writeLong(mRequestTime); } /** Returns the client request to execute an app function. */ @@ -96,4 +102,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { public String getCallingPackage() { return mCallingPackage; } + + /** Returns the time of calling executeAppFunction(). */ + public long getRequestTime() { + return mRequestTime; + } } diff --git a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java index 2426daf5c9f2..e290169bdea8 100644 --- a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java +++ b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java @@ -17,6 +17,7 @@ package android.app.appfunctions; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.RemoteException; import android.util.Log; @@ -37,8 +38,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { @NonNull private final IExecuteAppFunctionCallback mCallback; + @Nullable CompletionCallback mCompletionCallback; + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback) { + this(callback, /* completionCallback= */ null); + } + + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback, + @Nullable CompletionCallback completionCallback) { mCallback = Objects.requireNonNull(callback); + mCompletionCallback = completionCallback; } /** Invoke wrapped callback with the result. */ @@ -49,6 +58,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onSuccess(result); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnSuccess(result); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -63,6 +75,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onError(error); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnError(error); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -76,4 +91,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { public void disable() { mOnResultCalled.set(true); } + + /** + * Provides a hook to execute additional actions after the {@link IExecuteAppFunctionCallback} + * has been invoked. + */ + public interface CompletionCallback { + /** Called after {@link IExecuteAppFunctionCallback#onSuccess}. */ + void finalizeOnSuccess(@NonNull ExecuteAppFunctionResponse result); + + /** Called after {@link IExecuteAppFunctionCallback#onError}. */ + void finalizeOnError(@NonNull AppFunctionException error); + } } 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/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java index 469521668d25..a04f96a9f6e3 100644 --- a/core/java/android/app/jank/JankTracker.java +++ b/core/java/android/app/jank/JankTracker.java @@ -29,6 +29,7 @@ import android.view.ViewTreeObserver; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.HashMap; /** * This class is responsible for registering callbacks that will receive JankData batches. @@ -174,6 +175,15 @@ public class JankTracker { } /** + * Retrieve all pending jank stats before they are logged, this is intended for testing + * purposes only. + */ + @VisibleForTesting + public HashMap<String, JankDataProcessor.PendingJankStat> getPendingJankStats() { + return mJankDataProcessor.getPendingJankStats(); + } + + /** * Only intended to be used by tests, the runnable that registers the listeners may not run * in time for tests to pass. This forces them to run immediately. */ @@ -192,7 +202,11 @@ public class JankTracker { */ } - private boolean shouldTrack() { + /** + * Returns whether jank tracking is enabled or not. + */ + @VisibleForTesting + public boolean shouldTrack() { return mTrackingEnabled && mListenersRegistered; } diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index 7543fa9f581f..b1db1379e400 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -291,6 +291,13 @@ flag { } flag { + name: "nm_binder_perf_throttle_notify" + namespace: "systemui" + description: "Rate-limit calls to enqueueNotificationWithTag client-side" + bug: "362981561" +} + +flag { name: "no_sbnholder" namespace: "systemui" description: "removes sbnholder from NLS" diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 40de2985f68a..67ad4594599f 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -37,36 +37,44 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.Intent.FilterComparison; import android.content.IntentSender; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.Rect; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import com.android.internal.util.FunctionalUtils; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.function.Consumer; /** * Updates AppWidget state; gets information about installed AppWidget providers and other @@ -592,6 +600,8 @@ public class AppWidgetManager { private boolean mHasPostedLegacyLists = false; + private @NonNull ServiceCollectionCache mServiceCollectionCache; + /** * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context * Context} object. @@ -612,6 +622,7 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); + mServiceCollectionCache = new ServiceCollectionCache(context, /* timeout= */ 5000L); if (mService == null) { return; } @@ -649,7 +660,7 @@ public class AppWidgetManager { final RemoteViews viewsCopy = new RemoteViews(original); Runnable updateWidgetWithTask = () -> { try { - viewsCopy.collectAllIntents(mMaxBitmapMemory).get(); + viewsCopy.collectAllIntents(mMaxBitmapMemory, mServiceCollectionCache).get(); action.acceptOrThrow(viewsCopy); } catch (Exception e) { Log.e(TAG, failureMsg, e); @@ -1629,4 +1640,106 @@ public class AppWidgetManager { thread.start(); return thread.getThreadHandler(); } + + /** + * @hide + */ + public static class ServiceCollectionCache { + + private final Context mContext; + private final Handler mHandler; + private final long mTimeOut; + + private final Map<FilterComparison, ConnectionTask> mActiveConnections = + new ArrayMap<>(); + + public ServiceCollectionCache(Context context, long timeOut) { + mContext = context; + mHandler = new Handler(BackgroundThread.getHandler().getLooper()); + mTimeOut = timeOut; + } + + /** + * Connect to the service indicated by the {@code Intent}, and consume the binder on the + * specified executor + */ + public void connectAndConsume(Intent intent, Consumer<IBinder> task, Executor executor) { + mHandler.post(() -> connectAndConsumeInner(intent, task, executor)); + } + + private void connectAndConsumeInner(Intent intent, Consumer<IBinder> task, + Executor executor) { + ConnectionTask activeConnection = mActiveConnections.computeIfAbsent( + new FilterComparison(intent), ConnectionTask::new); + activeConnection.add(task, executor); + } + + private class ConnectionTask implements ServiceConnection { + + private final Runnable mDestroyAfterTimeout = this::onDestroyTimeout; + private final ArrayDeque<Pair<Consumer<IBinder>, Executor>> mTaskQueue = + new ArrayDeque<>(); + + private boolean mOnDestroyTimeout = false; + private IBinder mIBinder; + + ConnectionTask(@NonNull FilterComparison filter) { + mContext.bindService(filter.getIntent(), + Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), + mHandler::post, + this); + } + + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + mIBinder = iBinder; + mHandler.post(this::handleNext); + } + + @Override + public void onNullBinding(ComponentName name) { + // Use an empty binder, follow up tasks will handle the failure + onServiceConnected(name, new Binder()); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { } + + void add(Consumer<IBinder> task, Executor executor) { + mTaskQueue.add(Pair.create(task, executor)); + if (mOnDestroyTimeout) { + // If we are waiting for timeout, cancel it and execute the next task + handleNext(); + } + } + + private void handleNext() { + mHandler.removeCallbacks(mDestroyAfterTimeout); + Pair<Consumer<IBinder>, Executor> next = mTaskQueue.pollFirst(); + if (next != null) { + mOnDestroyTimeout = false; + next.second.execute(() -> { + next.first.accept(mIBinder); + mHandler.post(this::handleNext); + }); + } else { + // Finished all tasks, start a timeout to unbind this service + mOnDestroyTimeout = true; + mHandler.postDelayed(mDestroyAfterTimeout, mTimeOut); + } + } + + /** + * Called after we have waited for {@link #mTimeOut} after the last task is finished + */ + private void onDestroyTimeout() { + if (!mTaskQueue.isEmpty()) { + handleNext(); + return; + } + mContext.unbindService(this); + mActiveConnections.values().remove(this); + } + } + } } diff --git a/core/java/android/companion/DeviceId.java b/core/java/android/companion/DeviceId.java index f66a1ae5c175..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; @@ -154,8 +153,12 @@ public final class DeviceId implements Parcelable { /** * A builder for {@link DeviceId} + * + * <p>Calling apps must provide at least one of the following to identify + * 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; @@ -171,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 " @@ -191,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/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index b3f09a98d623..ed2fd99c55c5 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -1290,7 +1290,11 @@ public final class VirtualDeviceManager { @NonNull UserHandle user) {} /** - * Called when a window with a secure surface is no longer shown on the device. + * Called when there is no longer any window with a secure surface shown on the device. + * + * <p>This is only called once there are no more secure windows shown on the device. If + * there are multiple secure windows shown on the device, this callback will be called only + * once all of them are hidden.</p> * * @param displayId The display ID on which the window was shown before. * diff --git a/core/java/android/content/EventLogTags.logtags b/core/java/android/content/EventLogTags.logtags index 21ea90ad2e1e..861a5b72c86c 100644 --- a/core/java/android/content/EventLogTags.logtags +++ b/core/java/android/content/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.content; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a6492d36cf8f..3d75423edfa9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -12291,7 +12291,6 @@ public class Intent implements Parcelable, Cloneable { private IBinder mCreatorToken; // Stores all extra keys whose values are intents for a top level intent. private ArraySet<NestedIntentKey> mNestedIntentKeys; - } /** @@ -12353,6 +12352,7 @@ public class Intent implements Parcelable, Cloneable { public int hashCode() { return Objects.hash(mType, mKey, mIndex); } + } private @Nullable CreatorTokenInfo mCreatorTokenInfo; @@ -12416,7 +12416,7 @@ public class Intent implements Parcelable, Cloneable { // removeLaunchSecurityProtection() is called before it is launched. value = null; } - if (value instanceof Intent intent && !visited.contains(intent)) { + if (value instanceof Intent intent) { handleNestedIntent(intent, visited, new NestedIntentKey( NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL, key, 0)); } else if (value instanceof Parcelable[] parcelables) { @@ -12439,7 +12439,6 @@ public class Intent implements Parcelable, Cloneable { } private void handleNestedIntent(Intent intent, Set<Intent> visited, NestedIntentKey key) { - visited.add(intent); if (mCreatorTokenInfo == null) { mCreatorTokenInfo = new CreatorTokenInfo(); } @@ -12447,7 +12446,10 @@ public class Intent implements Parcelable, Cloneable { mCreatorTokenInfo.mNestedIntentKeys = new ArraySet<>(); } mCreatorTokenInfo.mNestedIntentKeys.add(key); - intent.collectNestedIntentKeysRecur(visited); + if (!visited.contains(intent)) { + visited.add(intent); + intent.collectNestedIntentKeysRecur(visited); + } } private void handleParcelableArray(Parcelable[] parcelables, String key, Set<Intent> visited) { diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index 44f2a4ca38e2..23f1ff8926df 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -158,6 +158,17 @@ ] }, { + "name": "CtsPackageInstallerCUJUpdateOwnerShipTestCases", + "options":[ + { + "exclude-annotation":"androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation":"org.junit.Ignore" + } + ] + }, + { "name": "CtsPackageInstallerCUJUpdateSelfTestCases", "options":[ { diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 18a45d8d442e..53813012b4b3 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -539,9 +539,6 @@ public class ApkLiteParseUtils { hasBindDeviceAdminPermission); break; case TAG_USES_SDK_LIBRARY: - if (!android.content.pm.Flags.sdkDependencyInstaller()) { - break; - } String usesSdkLibName = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "name"); // TODO(b/379219371): Due to a bug in bundletool, some apps can use diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig index 6fc7d90a8237..ecb4bb1394b6 100644 --- a/core/java/android/content/res/flags.aconfig +++ b/core/java/android/content/res/flags.aconfig @@ -114,3 +114,11 @@ flag { bug: "373535266" is_fixed_read_only: true } + +flag { + name: "self_targeting_android_resource_frro" + is_exported: true + namespace: "customization_picker" + description: "Fixes bug in Launcher preview by enabling overlays targeting 'android'" + bug: "377545987" +}
\ No newline at end of file diff --git a/core/java/android/content/res/loader/ResourcesProvider.java b/core/java/android/content/res/loader/ResourcesProvider.java index 830b7e0fa2d0..7eba1819d148 100644 --- a/core/java/android/content/res/loader/ResourcesProvider.java +++ b/core/java/android/content/res/loader/ResourcesProvider.java @@ -25,6 +25,7 @@ import android.content.om.OverlayManager; import android.content.pm.ApplicationInfo; import android.content.res.ApkAssets; import android.content.res.AssetFileDescriptor; +import android.content.res.Flags; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -90,6 +91,10 @@ public class ResourcesProvider implements AutoCloseable, Closeable { throws IOException { Objects.requireNonNull(overlayInfo); Preconditions.checkArgument(overlayInfo.isFabricated(), "Not accepted overlay"); + if (!Flags.selfTargetingAndroidResourceFrro()) { + Preconditions.checkStringNotEmpty( + overlayInfo.getTargetOverlayableName(), "Without overlayable name"); + } final String overlayName = OverlayManagerImpl.checkOverlayNameValid(overlayInfo.getOverlayName()); final String path = diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig index d8d4e161006c..9c811fb84da3 100644 --- a/core/java/android/credentials/flags.aconfig +++ b/core/java/android/credentials/flags.aconfig @@ -124,3 +124,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + namespace: "credential_manager" + name: "settings_w_fixes" + description: "Settings improvements for credential manager" + bug: "373711451" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/credentials/selection/IntentFactory.java b/core/java/android/credentials/selection/IntentFactory.java index c521b96fd8ee..59539c40d636 100644 --- a/core/java/android/credentials/selection/IntentFactory.java +++ b/core/java/android/credentials/selection/IntentFactory.java @@ -16,7 +16,7 @@ package android.credentials.selection; -import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED; +import static android.credentials.flags.Flags.FLAG_PROPAGATE_USER_CONTEXT_FOR_INTENT_CREATION; import static android.credentials.flags.Flags.configurableSelectorUiEnabled; import android.annotation.FlaggedApi; @@ -24,6 +24,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.TestApi; +import android.annotation.UserIdInt; +import android.app.AppGlobals; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -32,6 +34,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.IBinder; import android.os.Parcel; +import android.os.RemoteException; import android.os.ResultReceiver; import android.text.TextUtils; import android.util.Slog; @@ -46,7 +49,7 @@ import java.util.ArrayList; * @hide */ @TestApi -@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED) +@FlaggedApi(FLAG_PROPAGATE_USER_CONTEXT_FOR_INTENT_CREATION) public class IntentFactory { /** @@ -65,9 +68,10 @@ public class IntentFactory { @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, - @NonNull ResultReceiver resultReceiver) { + @NonNull ResultReceiver resultReceiver, + @UserIdInt int userId) { return createCredentialSelectorIntentInternal(context, requestInfo, - disabledProviderDataList, resultReceiver); + disabledProviderDataList, resultReceiver, userId); } /** @@ -96,9 +100,10 @@ public class IntentFactory { @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, - @NonNull ResultReceiver resultReceiver) { + @NonNull ResultReceiver resultReceiver, + @UserIdInt int userId) { IntentCreationResult result = createCredentialSelectorIntentInternal(context, requestInfo, - disabledProviderDataList, resultReceiver); + disabledProviderDataList, resultReceiver, userId); result.getIntent().putParcelableArrayListExtra( ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); return result; @@ -130,9 +135,10 @@ public class IntentFactory { @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, - @NonNull ResultReceiver resultReceiver) { + @NonNull ResultReceiver resultReceiver, @UserIdInt int userId) { return createCredentialSelectorIntentForCredMan(context, requestInfo, - enabledProviderDataList, disabledProviderDataList, resultReceiver).getIntent(); + enabledProviderDataList, disabledProviderDataList, resultReceiver, + userId).getIntent(); } /** @@ -142,10 +148,10 @@ public class IntentFactory { @NonNull public static Intent createCancelUiIntent(@NonNull Context context, @NonNull IBinder requestToken, boolean shouldShowCancellationUi, - @NonNull String appPackageName) { + @NonNull String appPackageName, @UserIdInt int userId) { Intent intent = new Intent(); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); - setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); + setCredentialSelectorUiComponentName(context, intent, intentResultBuilder, userId); intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST, new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi, appPackageName)); @@ -162,10 +168,10 @@ public class IntentFactory { @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, - @NonNull ResultReceiver resultReceiver) { + @NonNull ResultReceiver resultReceiver, @UserIdInt int userId) { Intent intent = new Intent(); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); - setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); + setCredentialSelectorUiComponentName(context, intent, intentResultBuilder, userId); intent.putParcelableArrayListExtra( ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList); intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo); @@ -175,9 +181,11 @@ public class IntentFactory { } private static void setCredentialSelectorUiComponentName(@NonNull Context context, - @NonNull Intent intent, @NonNull IntentCreationResult.Builder intentResultBuilder) { + @NonNull Intent intent, @NonNull IntentCreationResult.Builder intentResultBuilder, + @UserIdInt int userId) { if (configurableSelectorUiEnabled()) { - ComponentName componentName = getOemOverrideComponentName(context, intentResultBuilder); + ComponentName componentName = getOemOverrideComponentName(context, + intentResultBuilder, userId); ComponentName fallbackUiComponentName = null; try { @@ -210,7 +218,7 @@ public class IntentFactory { */ @Nullable private static ComponentName getOemOverrideComponentName(@NonNull Context context, - @NonNull IntentCreationResult.Builder intentResultBuilder) { + @NonNull IntentCreationResult.Builder intentResultBuilder, @UserIdInt int userId) { ComponentName result = null; String oemComponentString = Resources.getSystem() @@ -228,35 +236,43 @@ public class IntentFactory { if (oemComponentName != null) { try { intentResultBuilder.setOemUiPackageName(oemComponentName.getPackageName()); - ActivityInfo info = context.getPackageManager().getActivityInfo( - oemComponentName, - PackageManager.ComponentInfoFlags.of( - PackageManager.MATCH_SYSTEM_ONLY)); - boolean oemComponentEnabled = info.enabled; - int runtimeComponentEnabledState = context.getPackageManager() + ActivityInfo info; + if (android.credentials.flags.Flags.propagateUserContextForIntentCreation()) { + info = context.getPackageManager().getActivityInfo(oemComponentName, + PackageManager.ComponentInfoFlags.of( + PackageManager.MATCH_SYSTEM_ONLY)); + } else { + info = AppGlobals.getPackageManager().getActivityInfo( + oemComponentName, 0, userId); + } + boolean oemComponentEnabled = false; + if (info != null) { + oemComponentEnabled = info.enabled; + int runtimeComponentEnabledState = context.getPackageManager() .getComponentEnabledSetting(oemComponentName); - if (runtimeComponentEnabledState == PackageManager + if (runtimeComponentEnabledState == PackageManager .COMPONENT_ENABLED_STATE_ENABLED) { - oemComponentEnabled = true; - } else if (runtimeComponentEnabledState == PackageManager + oemComponentEnabled = true; + } else if (runtimeComponentEnabledState == PackageManager .COMPONENT_ENABLED_STATE_DISABLED) { oemComponentEnabled = false; - } - if (oemComponentEnabled && info.exported) { + } + if (oemComponentEnabled && info.exported) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult - .OemUiUsageStatus.SUCCESS); + .OemUiUsageStatus.SUCCESS); Slog.i(TAG, - "Found enabled oem CredMan UI component." - + oemComponentString); + "Found enabled oem CredMan UI component." + + oemComponentString); result = oemComponentName; - } else { - intentResultBuilder.setOemUiUsageStatus(IntentCreationResult - .OemUiUsageStatus.OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED); - Slog.i(TAG, - "Found enabled oem CredMan UI component but it was not " - + "enabled."); + } else { + intentResultBuilder.setOemUiUsageStatus(IntentCreationResult + .OemUiUsageStatus.OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED); + Slog.i(TAG, + "Found enabled oem CredMan UI component but it was not " + + "enabled."); + } } - } catch (PackageManager.NameNotFoundException e) { + } catch (RemoteException | PackageManager.NameNotFoundException e) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND); Slog.i(TAG, "Unable to find oem CredMan UI component: " diff --git a/core/java/android/database/sqlite/SQLiteRawStatement.java b/core/java/android/database/sqlite/SQLiteRawStatement.java index c59d3cea0414..3f3e46b4334c 100644 --- a/core/java/android/database/sqlite/SQLiteRawStatement.java +++ b/core/java/android/database/sqlite/SQLiteRawStatement.java @@ -554,10 +554,16 @@ public final class SQLiteRawStatement implements Closeable { * * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_type</a> * + * If the row has no data then a {@link SQLiteMisuseException} is thrown. This condition can + * occur the last call to {@link #step()} returned false or if {@link #step()} was not called + * before the statement was created or after the last call to {@link #reset()}. Note that + * {@link SQLiteMisuseException} may be thrown for other reasons. + * * @param columnIndex The index of a column in the result row. It is zero-based. * @return The type of the value in the column of the result row. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. * @throws SQLiteException if a native error occurs. */ @SQLiteDataType @@ -580,6 +586,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The name of the column in the result row. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteOutOfMemoryException if the database cannot allocate memory for the name. */ @NonNull @@ -606,6 +613,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The length, in bytes, of the value in the column. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int getColumnLength(int columnIndex) { @@ -631,6 +639,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as a blob, or null if the column is NULL. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ @Nullable @@ -664,6 +673,7 @@ public final class SQLiteRawStatement implements Closeable { * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws IllegalArgumentException if the buffer is too small for offset+length. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int readColumnBlob(int columnIndex, @NonNull byte[] buffer, int offset, @@ -691,6 +701,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of a column as a double. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public double getColumnDouble(int columnIndex) { @@ -715,6 +726,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as an int. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public int getColumnInt(int columnIndex) { @@ -739,6 +751,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as an long. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ public long getColumnLong(int columnIndex) { @@ -763,6 +776,7 @@ public final class SQLiteRawStatement implements Closeable { * @return The value of the column as a string. * @throws IllegalStateException if the statement is closed or this is a foreign thread. * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range. + * @throws SQLiteMisuseException if the row has no data. See {@link #getColumnType()}. * @throws SQLiteException if a native error occurs. */ @NonNull diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java index b8af398a7594..77f937ebeabc 100644 --- a/core/java/android/hardware/contexthub/HubEndpointSession.java +++ b/core/java/android/hardware/contexthub/HubEndpointSession.java @@ -69,6 +69,8 @@ public class HubEndpointSession implements AutoCloseable { * @return For messages that does not require a response, the transaction will immediately * complete. For messages that requires a response, the transaction will complete after * receiving the response for the message. + * @throws SecurityException if the application doesn't have the right permissions to send this + * message. */ @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) 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/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 310e1a64d84e..d9888ad6cd8d 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -841,6 +841,7 @@ public final class ContextHubManager { * @param endpointId The identifier of the hub endpoint. * @param callback The callback to be invoked. * @param executor The executor to invoke the callback on. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -881,6 +882,7 @@ public final class ContextHubManager { * @param callback The callback to be invoked. * @param executor The executor to invoke the callback on. * @throws IllegalArgumentException if the serviceDescriptor is empty. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -911,6 +913,7 @@ public final class ContextHubManager { * * @param callback The callback previously registered. * @throws IllegalArgumentException If the callback was not previously registered. + * @throws UnsupportedOperationException If the operation is not supported. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) @@ -1311,6 +1314,8 @@ public final class ContextHubManager { * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}). * @param serviceDescriptor A string that describes the service associated with this session. * The information will be sent to the destination as part of open request. + * @throws IllegalStateException if hubEndpoint was not successfully registered, or if there is + * insufficient capacity for creating a session. */ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @FlaggedApi(Flags.FLAG_OFFLOAD_API) 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/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 5f3c15d1842e..4c9e73c8b21f 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -3202,7 +3202,8 @@ public class InputMethodService extends AbstractInputMethodService { */ @FlaggedApi(Flags.FLAG_ADAPTIVE_HANDWRITING_BOUNDS) public final void setStylusHandwritingRegion(@NonNull Region handwritingRegion) { - if (handwritingRegion.equals(mLastHandwritingRegion)) { + final Region immutableHandwritingRegion = new Region(handwritingRegion); + if (immutableHandwritingRegion.equals(mLastHandwritingRegion)) { Log.v(TAG, "Failed to set setStylusHandwritingRegion():" + " same region set twice."); return; @@ -3210,10 +3211,10 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) { Log.d(TAG, "Setting new handwriting region for stylus handwriting " - + handwritingRegion + " from last " + mLastHandwritingRegion); + + immutableHandwritingRegion + " from last " + mLastHandwritingRegion); } - mPrivOps.setHandwritingTouchableRegion(handwritingRegion); - mLastHandwritingRegion = handwritingRegion; + mPrivOps.setHandwritingTouchableRegion(immutableHandwritingRegion); + mLastHandwritingRegion = immutableHandwritingRegion; } /** diff --git a/core/java/android/net/EventLogTags.logtags b/core/java/android/net/EventLogTags.logtags index d5ed01496eba..32953c92d120 100644 --- a/core/java/android/net/EventLogTags.logtags +++ b/core/java/android/net/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.net diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index b44f75a585d5..3425b77be954 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -22,7 +22,7 @@ import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.net.platform.flags.Flags; +import android.security.Flags; import android.security.net.config.UserCertificateSource; import com.android.org.conscrypt.TrustManagerImpl; @@ -152,7 +152,7 @@ public class X509TrustManagerExtensions { * @throws IllegalArgumentException if the TrustManager is not compatible. * @return the properly ordered chain used for verification as a list of X509Certificates. */ - @FlaggedApi(Flags.FLAG_X509_EXTENSIONS_CERTIFICATE_TRANSPARENCY) + @FlaggedApi(Flags.FLAG_CERTIFICATE_TRANSPARENCY_CONFIGURATION) @NonNull public List<X509Certificate> checkServerTrusted( @SuppressLint("ArrayReturn") @NonNull X509Certificate[] chain, diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 11b80ceaeace..230fa3fec930 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -1272,7 +1272,7 @@ public final class MessageQueue { return true; } - private Message legacyPeekOrPop(boolean peek) { + private Message legacyPeekOrPoll(boolean peek) { synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); @@ -1331,7 +1331,7 @@ public final class MessageQueue { if (mUseConcurrent) { ret = nextMessage(true); } else { - ret = legacyPeekOrPop(true); + ret = legacyPeekOrPoll(true); } return ret != null ? ret.when : null; } @@ -1344,15 +1344,81 @@ public final class MessageQueue { */ @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this @Nullable - Message popForTest() { + Message pollForTest() { throwIfNotTest(); if (mUseConcurrent) { return nextMessage(false); } else { - return legacyPeekOrPop(false); + return legacyPeekOrPoll(false); } } + /** + * @return true if we are blocked on a sync barrier + * + * Calls to this method must not be allowed to race with `next`. + * Specifically, the Looper thread must be paused before calling this method, + * and may not be resumed until after returning from this method. + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + if (mUseConcurrent) { + // Call nextMessage to get the stack drained into our priority queues + nextMessage(true); + + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode != null && 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 != null && queueNode.isBarrier()) { + queueNode = iterateNext(queueIter); + } + if (queueNode != null && now >= queueNode.getWhen()) { + return true; + } + } + } 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; + } + 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..d7d8e4199b33 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -19,6 +19,7 @@ package android.os; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.app.ActivityThread; import android.app.Instrumentation; @@ -784,7 +785,7 @@ public final class MessageQueue { mMessageDirectlyQueued = false; nativePollOnce(ptr, mNextPollTimeoutMillis); - Message msg = nextMessage(); + Message msg = nextMessage(false); if (msg != null) { msg.markInUse(); return msg; @@ -1087,7 +1088,6 @@ public final class MessageQueue { * * Caller must ensure that this doesn't race 'next' from the Looper thread. */ - @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this Long peekWhenForTest() { throwIfNotTest(); Message ret = nextMessage(true); @@ -1100,13 +1100,51 @@ public final class MessageQueue { * * Caller must ensure that this doesn't race 'next' from the Looper thread. */ - @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this @Nullable - Message popForTest() { + Message pollForTest() { throwIfNotTest(); return nextMessage(false); } + /** + * @return true if we are blocked on a sync barrier + * + * Calls to this method must not be allowed to race with `next`. + * Specifically, the Looper thread must be paused before calling this method, + * and may not be resumed until after returning from this method. + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + + // Call nextMessage to get the stack drained into our priority queues + nextMessage(true); + + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode != null && 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 != null && 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; @@ -1161,7 +1199,7 @@ public final class MessageQueue { MessageNode p = (MessageNode) top; while (true) { - if (compare.compareMessage(p.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(p, h, what, object, r, when)) { found = true; if (DEBUG) { Log.w(TAG, "stackHasMessages node matches"); @@ -1206,7 +1244,7 @@ public final class MessageQueue { while (iterator.hasNext()) { MessageNode msg = iterator.next(); - if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) { + if (compare.compareMessage(msg, h, what, object, r, when)) { if (removeMatches) { found = true; if (queue.remove(msg)) { diff --git a/core/java/android/os/EventLogTags.logtags b/core/java/android/os/EventLogTags.logtags index b143a7443066..f57aad00e591 100644 --- a/core/java/android/os/EventLogTags.logtags +++ b/core/java/android/os/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.os diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 4a14a8d0faf8..56a089aff78a 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -21,11 +21,13 @@ import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.os.SessionCreationConfig; -import android.hardware.power.CpuHeadroomResult; + import android.hardware.power.ChannelConfig; +import android.hardware.power.CpuHeadroomResult; import android.hardware.power.GpuHeadroomResult; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; +import android.hardware.power.SupportInfo; /** {@hide} */ interface IHintManager { @@ -40,11 +42,6 @@ interface IHintManager { IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag, in SessionCreationConfig creationConfig, out SessionConfig config); - /** - * Get preferred rate limit in nanoseconds. - */ - long getHintSessionPreferredRate(); - void setHintSessionThreads(in IHintSession hintSession, in int[] tids); int[] getHintSessionThreadIds(in IHintSession hintSession); @@ -61,13 +58,28 @@ interface IHintManager { long getGpuHeadroomMinIntervalMillis(); /** - * Get Maximum number of graphics pipeline threads allowed per-app. - */ - int getMaxGraphicsPipelineThreadsCount(); - - /** * Used by the JNI to pass an interface to the SessionManager; * for internal use only. */ oneway void passSessionManagerBinder(in IBinder sessionManager); + + parcelable HintManagerClientData { + int powerHalVersion; + int maxGraphicsPipelineThreads; + long preferredRateNanos; + SupportInfo supportInfo; + } + + interface IHintManagerClient { + /** + * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan. + */ + oneway void receiveChannelConfig(in ChannelConfig config); + } + + /** + * Set up an ADPF client, receiving a remote client binder interface and + * passing back a bundle of support and configuration information. + */ + HintManagerClientData registerClient(in IHintManagerClient client); } diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index f49acd1edf1a..c0333e914b4d 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -740,7 +740,7 @@ public final class MessageQueue { return true; } - private Message legacyPeekOrPop(boolean peek) { + private Message legacyPeekOrPoll(boolean peek) { synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); @@ -795,7 +795,7 @@ public final class MessageQueue { @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this Long peekWhenForTest() { throwIfNotTest(); - Message ret = legacyPeekOrPop(true); + Message ret = legacyPeekOrPoll(true); return ret != null ? ret.when : null; } @@ -807,9 +807,47 @@ public final class MessageQueue { */ @SuppressLint("VisiblySynchronized") // Legacy MessageQueue synchronizes on this @Nullable - Message popForTest() { + Message pollForTest() { throwIfNotTest(); - return legacyPeekOrPop(false); + return legacyPeekOrPoll(false); + } + + /** + * @return true if we are blocked on a sync barrier + * + * Calls to this method must not be allowed to race with `next`. + * Specifically, the Looper thread must be paused before calling this method, + * and may not be resumed until after returning from this method. + */ + 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) { diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 6855d95d718f..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; } @@ -932,9 +892,14 @@ public final class Parcel { /** * Report whether the parcel contains any marshalled file descriptors. + * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. */ public boolean hasFileDescriptors() { - assertNotRecycled(); return nativeHasFileDescriptors(mNativePtr); } @@ -942,6 +907,12 @@ public final class Parcel { * Report whether the parcel contains any marshalled file descriptors in the range defined by * {@code offset} and {@code length}. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @param offset The offset from which the range starts. Should be between 0 and * {@link #dataSize()}. * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code @@ -950,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); } @@ -963,6 +933,12 @@ public final class Parcel { * <p>For most cases, it will use the self-reported {@link Parcelable#describeContents()} method * for that. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @throws IllegalArgumentException if you provide any object not supported by above methods * (including if the unsupported object is inside a nested container). * @@ -1032,10 +1008,16 @@ public final class Parcel { * * @throws UnsupportedOperationException if binder kernel driver was disabled or if method was * invoked in case of Binder RPC protocol. + * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @hide */ public boolean hasBinders() { - assertNotRecycled(); return nativeHasBinders(mNativePtr); } @@ -1043,6 +1025,12 @@ public final class Parcel { * Report whether the parcel contains any marshalled {@link IBinder} objects in the range * defined by {@code offset} and {@code length}. * + * WARNING: Parcelable definitions change over time. Unless you define + * a Parcelable yourself OR the Parcelable explicitly guarantees that + * it would never include such objects, you should not expect the return + * value to stay the same, and your code should continue to work even + * if the return value changes. + * * @param offset The offset from which the range starts. Should be between 0 and * {@link #dataSize()}. * @param length The length of the range. Should be between 0 and {@link #dataSize()} - {@code @@ -1053,7 +1041,6 @@ public final class Parcel { * @hide */ public boolean hasBinders(int offset, int length) { - assertNotRecycled(); return nativeHasBindersInRange(mNativePtr, offset, length); } @@ -1064,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); } @@ -1075,7 +1061,6 @@ public final class Parcel { * should propagate to the caller. */ public final void enforceInterface(@NonNull String interfaceName) { - assertNotRecycled(); nativeEnforceInterface(mNativePtr, interfaceName); } @@ -1086,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); @@ -1103,7 +1087,6 @@ public final class Parcel { * @hide */ public boolean replaceCallingWorkSourceUid(int workSourceUid) { - assertNotRecycled(); return nativeReplaceCallingWorkSourceUid(mNativePtr, workSourceUid); } @@ -1120,7 +1103,6 @@ public final class Parcel { * @hide */ public int readCallingWorkSourceUid() { - assertNotRecycled(); return nativeReadCallingWorkSourceUid(mNativePtr); } @@ -1130,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); } @@ -1142,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; @@ -1164,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); } @@ -1183,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; @@ -1202,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); @@ -1214,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); @@ -1226,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); @@ -1238,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); @@ -1250,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); } @@ -1274,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); } @@ -1298,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); } @@ -1310,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); } @@ -1319,7 +1285,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeStrongBinder(IBinder val) { - assertNotRecycled(); nativeWriteStrongBinder(mNativePtr, val); } @@ -1328,7 +1293,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeStrongInterface(IInterface val) { - assertNotRecycled(); writeStrongBinder(val == null ? null : val.asBinder()); } @@ -1343,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); } @@ -1352,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); } @@ -1363,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); @@ -1383,7 +1344,6 @@ public final class Parcel { * the future. */ public final void writeByte(byte val) { - assertNotRecycled(); writeInt(val); } @@ -1399,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); } @@ -1408,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; @@ -1434,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; @@ -1464,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); } @@ -1483,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; @@ -1505,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++) { @@ -1518,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; @@ -1532,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; @@ -1546,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()); } @@ -1556,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()); } @@ -1567,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; @@ -1587,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; @@ -1608,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; @@ -1624,7 +1571,6 @@ public final class Parcel { } public final void writeSparseBooleanArray(@Nullable SparseBooleanArray val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1643,7 +1589,6 @@ public final class Parcel { * @hide */ public final void writeSparseIntArray(@Nullable SparseIntArray val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1659,7 +1604,6 @@ public final class Parcel { } public final void writeBooleanArray(@Nullable boolean[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1694,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; @@ -1712,7 +1655,6 @@ public final class Parcel { } private void ensureWithinMemoryLimit(int typeSize, int length) { - assertNotRecycled(); int estimatedAllocationSize = 0; try { estimatedAllocationSize = Math.multiplyExact(typeSize, length); @@ -1736,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 @@ -1754,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++) { @@ -1767,7 +1707,6 @@ public final class Parcel { /** @hide */ public void writeShortArray(@Nullable short[] val) { - assertNotRecycled(); if (val != null) { int n = val.length; writeInt(n); @@ -1782,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)) { @@ -1798,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++) { @@ -1810,7 +1747,6 @@ public final class Parcel { } public final void writeCharArray(@Nullable char[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1824,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)) { @@ -1839,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++) { @@ -1851,7 +1785,6 @@ public final class Parcel { } public final void writeIntArray(@Nullable int[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1865,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)) { @@ -1880,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++) { @@ -1892,7 +1823,6 @@ public final class Parcel { } public final void writeLongArray(@Nullable long[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1906,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 @@ -1922,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++) { @@ -1934,7 +1862,6 @@ public final class Parcel { } public final void writeFloatArray(@Nullable float[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1948,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 @@ -1964,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++) { @@ -1976,7 +1901,6 @@ public final class Parcel { } public final void writeDoubleArray(@Nullable double[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1990,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 @@ -2006,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++) { @@ -2018,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); @@ -2050,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) { @@ -2066,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++) { @@ -2079,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); @@ -2094,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) { @@ -2110,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++) { @@ -2122,7 +2035,6 @@ public final class Parcel { } public final void writeBinderArray(@Nullable IBinder[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2147,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); @@ -2163,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); @@ -2179,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); @@ -2193,7 +2102,6 @@ public final class Parcel { @Nullable public final IBinder[] createBinderArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { @@ -2208,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++) { @@ -2230,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) { @@ -2255,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++) { @@ -2281,7 +2186,6 @@ public final class Parcel { * @see Parcelable */ public final <T extends Parcelable> void writeTypedList(@Nullable List<T> val) { - assertNotRecycled(); writeTypedList(val, 0); } @@ -2301,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; @@ -2331,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; @@ -2357,7 +2259,6 @@ public final class Parcel { * @see #readStringList */ public final void writeStringList(@Nullable List<String> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2383,7 +2284,6 @@ public final class Parcel { * @see #readBinderList */ public final void writeBinderList(@Nullable List<IBinder> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2406,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; @@ -2428,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; @@ -2463,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); @@ -2486,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); @@ -2524,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; @@ -2636,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); @@ -2754,7 +2648,6 @@ public final class Parcel { * @hide */ public void writeValue(int type, @Nullable Object v) { - assertNotRecycled(); switch (type) { case VAL_NULL: break; @@ -2868,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; @@ -2884,7 +2776,6 @@ public final class Parcel { * @see #readParcelableCreator */ public final void writeParcelableCreator(@NonNull Parcelable p) { - assertNotRecycled(); String name = p.getClass().getName(); writeString(name); } @@ -2923,7 +2814,6 @@ public final class Parcel { */ @TestApi public boolean allowSquashing() { - assertNotRecycled(); boolean previous = mAllowSquashing; mAllowSquashing = true; return previous; @@ -2935,7 +2825,6 @@ public final class Parcel { */ @TestApi public void restoreAllowSquashing(boolean previous) { - assertNotRecycled(); mAllowSquashing = previous; if (!mAllowSquashing) { mWrittenSquashableParcelables = null; @@ -2992,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); @@ -3043,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(); @@ -3077,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; @@ -3130,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); @@ -3211,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(); @@ -3237,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"), @@ -3281,7 +3164,6 @@ public final class Parcel { * @see #writeNoException */ public final void readException() { - assertNotRecycled(); int code = readExceptionCode(); if (code != 0) { String msg = readString(); @@ -3305,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); @@ -3339,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) { @@ -3370,7 +3250,6 @@ public final class Parcel { /** @hide */ public Exception createExceptionOrNull(int code, String msg) { - assertNotRecycled(); switch (code) { case EX_PARCELABLE: if (readInt() > 0) { @@ -3403,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); } @@ -3411,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); } @@ -3420,7 +3297,6 @@ public final class Parcel { * dataPosition(). */ public final float readFloat() { - assertNotRecycled(); return nativeReadFloat(mNativePtr); } @@ -3429,7 +3305,6 @@ public final class Parcel { * current dataPosition(). */ public final double readDouble() { - assertNotRecycled(); return nativeReadDouble(mNativePtr); } @@ -3438,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); } @@ -3462,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); } @@ -3482,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; } @@ -3493,7 +3361,6 @@ public final class Parcel { @UnsupportedAppUsage @Nullable public final CharSequence readCharSequence() { - assertNotRecycled(); return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this); } @@ -3501,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 @@ -3517,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; } @@ -3525,7 +3390,6 @@ public final class Parcel { /** {@hide} */ @UnsupportedAppUsage public final FileDescriptor readRawFileDescriptor() { - assertNotRecycled(); return nativeReadFileDescriptor(mNativePtr); } @@ -3536,7 +3400,6 @@ public final class Parcel { **/ @Nullable public final FileDescriptor[] createRawFileDescriptorArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -3556,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++) { @@ -3571,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); } @@ -3586,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); } @@ -3600,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); @@ -3619,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); } @@ -3641,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); @@ -3661,7 +3518,6 @@ public final class Parcel { @Deprecated @Nullable public HashMap readHashMap(@Nullable ClassLoader loader) { - assertNotRecycled(); return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null); } @@ -3676,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); @@ -3689,7 +3544,6 @@ public final class Parcel { */ @Nullable public final Bundle readBundle() { - assertNotRecycled(); return readBundle(null); } @@ -3701,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); @@ -3722,7 +3575,6 @@ public final class Parcel { */ @Nullable public final PersistableBundle readPersistableBundle() { - assertNotRecycled(); return readPersistableBundle(null); } @@ -3734,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); @@ -3753,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); @@ -3764,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); @@ -3775,7 +3624,6 @@ public final class Parcel { */ @Nullable public final byte[] createByteArray() { - assertNotRecycled(); return nativeCreateByteArray(mNativePtr); } @@ -3784,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"); @@ -3797,7 +3644,6 @@ public final class Parcel { */ @Nullable public final byte[] readBlob() { - assertNotRecycled(); return nativeReadBlob(mNativePtr); } @@ -3808,7 +3654,6 @@ public final class Parcel { @UnsupportedAppUsage @Nullable public final String[] readStringArray() { - assertNotRecycled(); return createString16Array(); } @@ -3818,7 +3663,6 @@ public final class Parcel { */ @Nullable public final CharSequence[] readCharSequenceArray() { - assertNotRecycled(); CharSequence[] array = null; int length = readInt(); @@ -3841,7 +3685,6 @@ public final class Parcel { */ @Nullable public final ArrayList<CharSequence> readCharSequenceList() { - assertNotRecycled(); ArrayList<CharSequence> array = null; int length = readInt(); @@ -3871,7 +3714,6 @@ public final class Parcel { @Deprecated @Nullable public ArrayList readArrayList(@Nullable ClassLoader loader) { - assertNotRecycled(); return readArrayListInternal(loader, /* clazz */ null); } @@ -3894,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); } @@ -3914,7 +3755,6 @@ public final class Parcel { @Deprecated @Nullable public Object[] readArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readArrayInternal(loader, /* clazz */ null); } @@ -3936,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); } @@ -3956,7 +3795,6 @@ public final class Parcel { @Deprecated @Nullable public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readSparseArrayInternal(loader, /* clazz */ null); } @@ -3978,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); } @@ -3990,7 +3827,6 @@ public final class Parcel { */ @Nullable public final SparseBooleanArray readSparseBooleanArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4007,7 +3843,6 @@ public final class Parcel { */ @Nullable public final SparseIntArray readSparseIntArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4032,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; @@ -4056,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; @@ -4086,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; @@ -4116,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; @@ -4144,7 +3975,6 @@ public final class Parcel { */ @Nullable public final ArrayList<String> createStringArrayList() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4171,7 +4001,6 @@ public final class Parcel { */ @Nullable public final ArrayList<IBinder> createBinderArrayList() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4199,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; @@ -4220,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; @@ -4242,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; @@ -4265,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; @@ -4297,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); } @@ -4319,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); @@ -4365,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; @@ -4379,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++) { @@ -4396,7 +4217,6 @@ public final class Parcel { */ @Deprecated public final <T> T[] readTypedArray(Parcelable.Creator<T> c) { - assertNotRecycled(); return createTypedArray(c); } @@ -4413,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 { @@ -4440,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); @@ -4481,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); @@ -4508,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); @@ -4566,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 @@ -4640,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 @@ -4701,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 @@ -4765,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); @@ -4784,7 +4596,6 @@ public final class Parcel { */ @Nullable public final Object readValue(@Nullable ClassLoader loader) { - assertNotRecycled(); return readValue(loader, /* clazz */ null); } @@ -4840,7 +4651,6 @@ public final class Parcel { */ @Nullable public Object readLazyValue(@Nullable ClassLoader loader) { - assertNotRecycled(); int start = dataPosition(); int type = readInt(); if (isLengthPrefixed(type)) { @@ -5243,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); } @@ -5263,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); } @@ -5292,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; @@ -5320,7 +5127,6 @@ public final class Parcel { @Deprecated @Nullable public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) { - assertNotRecycled(); return readParcelableCreatorInternal(loader, /* clazz */ null); } @@ -5341,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); } @@ -5464,7 +5269,6 @@ public final class Parcel { @Deprecated @Nullable public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readParcelableArrayInternal(loader, /* clazz */ null); } @@ -5485,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)); } @@ -5519,7 +5322,6 @@ public final class Parcel { @Deprecated @Nullable public Serializable readSerializable() { - assertNotRecycled(); return readSerializableInternal(/* loader */ null, /* clazz */ null); } @@ -5536,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); @@ -5778,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; @@ -5795,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; @@ -5935,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 4b16c1dce463..e2169925fdd3 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -14,6 +14,8 @@ package android.os; +import android.annotation.FlaggedApi; +import android.annotation.Nullable; import android.util.ArraySet; import java.util.concurrent.LinkedBlockingQueue; @@ -93,9 +95,52 @@ public class TestLooperManager { } /** - * Releases the looper to continue standard looping and processing of messages, - * no further interactions with TestLooperManager will be allowed after - * release() has been called. + * Retrieves and removes the next message that should be executed by this queue. + * If the queue is empty or no messages are deliverable, returns null. + * This method never blocks. + * + * <p>Callers should always call {@link #recycle(Message)} on the message when all interactions + * with it have completed. + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + @Nullable + public Message poll() { + checkReleased(); + return mQueue.pollForTest(); + } + + /** + * Retrieves, but does not remove, the values of {@link Message#when} of next message that + * should be executed by this queue. + * If the queue is empty or no messages are deliverable, returns null. + * This method never blocks. + * + * <p>Callers should always call {@link #recycle(Message)} on the message when all interactions + * with it have completed. + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + @SuppressWarnings("AutoBoxing") // box the primitive long, or return null to indicate no value + @Nullable + public Long peekWhen() { + checkReleased(); + return mQueue.peekWhenForTest(); + } + + /** + * 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. */ public void release() { synchronized (sHeldLoopers) { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 7e73a5d04866..b9f2cfcd8ca8 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -6501,7 +6501,11 @@ public class UserManager { * @hide */ public static final void invalidateCacheOnUserDataChanged() { - if (android.multiuser.Flags.cacheProfilesReadOnly()) { + if (android.multiuser.Flags.cacheProfilesReadOnly() + || android.multiuser.Flags.cacheUserInfoReadOnly()) { + // TODO(b/383175685): Rename the invalidation call to make it clearer that it + // invalidates the caches for both getProfiles and getUserInfo (since they both use the + // same user_manager_user_data CachedProperty.api). UserManagerCache.invalidateProfiles(); } } diff --git a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl index c45c51d15cc9..af56bfe50381 100644 --- a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl +++ b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl @@ -16,7 +16,7 @@ package android.os.instrumentation; -import android.os.instrumentation.ExecutableMethodFileOffsets; +import android.os.instrumentation.IOffsetCallback; import android.os.instrumentation.MethodDescriptor; import android.os.instrumentation.TargetProcess; @@ -28,6 +28,7 @@ import android.os.instrumentation.TargetProcess; interface IDynamicInstrumentationManager { /** Provides ART metadata about the described compiled method within the target process */ @PermissionManuallyEnforced - @nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets( - in TargetProcess targetProcess, in MethodDescriptor methodDescriptor); + void getExecutableMethodFileOffsets( + in TargetProcess targetProcess, in MethodDescriptor methodDescriptor, + in IOffsetCallback callback); } diff --git a/core/java/android/os/instrumentation/IOffsetCallback.aidl b/core/java/android/os/instrumentation/IOffsetCallback.aidl new file mode 100644 index 000000000000..a28c93f5353a --- /dev/null +++ b/core/java/android/os/instrumentation/IOffsetCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.instrumentation; + +import android.os.instrumentation.ExecutableMethodFileOffsets; + +/** + * System private API for providing dynamic instrumentation offset results. + * + * {@hide} + */ +oneway interface IOffsetCallback { + void onResult(in @nullable ExecutableMethodFileOffsets offsets); +} diff --git a/core/java/android/os/instrumentation/MethodDescriptorParser.java b/core/java/android/os/instrumentation/MethodDescriptorParser.java new file mode 100644 index 000000000000..57fc44ff623e --- /dev/null +++ b/core/java/android/os/instrumentation/MethodDescriptorParser.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.instrumentation; + +import android.annotation.NonNull; + +import java.lang.reflect.Method; + +/** + * A utility class for dynamic instrumentation / uprobestats. + * + * @hide + */ +public final class MethodDescriptorParser { + + /** + * Parses a {@link MethodDescriptor} (in string representation) into a {@link Method}. + */ + public static Method parseMethodDescriptor(ClassLoader classLoader, + @NonNull MethodDescriptor descriptor) { + try { + Class<?> javaClass = classLoader.loadClass(descriptor.fullyQualifiedClassName); + Class<?>[] parameters = new Class[descriptor.fullyQualifiedParameters.length]; + for (int i = 0; i < descriptor.fullyQualifiedParameters.length; i++) { + String typeName = descriptor.fullyQualifiedParameters[i]; + boolean isArrayType = typeName.endsWith("[]"); + if (isArrayType) { + typeName = typeName.substring(0, typeName.length() - 2); + } + switch (typeName) { + case "boolean": + parameters[i] = isArrayType ? boolean.class.arrayType() : boolean.class; + break; + case "byte": + parameters[i] = isArrayType ? byte.class.arrayType() : byte.class; + break; + case "char": + parameters[i] = isArrayType ? char.class.arrayType() : char.class; + break; + case "short": + parameters[i] = isArrayType ? short.class.arrayType() : short.class; + break; + case "int": + parameters[i] = isArrayType ? int.class.arrayType() : int.class; + break; + case "long": + parameters[i] = isArrayType ? long.class.arrayType() : long.class; + break; + case "float": + parameters[i] = isArrayType ? float.class.arrayType() : float.class; + break; + case "double": + parameters[i] = isArrayType ? double.class.arrayType() : double.class; + break; + default: + parameters[i] = isArrayType ? classLoader.loadClass(typeName).arrayType() + : classLoader.loadClass(typeName); + } + } + + return javaClass.getDeclaredMethod(descriptor.methodName, parameters); + } catch (ClassNotFoundException | NoSuchMethodException e) { + throw new IllegalArgumentException( + "The specified method cannot be found. Is this descriptor valid? " + + descriptor, e); + } + } +} diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 2c4883f1f61c..af96ccfee787 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -57,7 +57,7 @@ flag { is_exported: true is_fixed_read_only: true namespace: "permissions" - description: "enable enhanced confirmation incall apis" + description: "DEPRECATED, does not gate any apis" bug: "364535720" } @@ -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/provider/Settings.java b/core/java/android/provider/Settings.java index 9935be2c8ef6..4acb6312f90d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10042,6 +10042,12 @@ public final class Settings { "minimal_post_processing_allowed"; /** + * Whether to mirror the built-in display on all connected displays. + * @hide + */ + public static final String MIRROR_BUILT_IN_DISPLAY = "mirror_built_in_display"; + + /** * No mode switching will happen. * * @see #MATCH_CONTENT_FRAME_RATE 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/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index fba8e42cc673..6d62a2c7db2e 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -341,7 +341,7 @@ public final class FillEventHistory implements Parcelable { /** Credential Manager suggestions are shown instead of Autofill suggestion */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) - public static final int UI_TYPE_CREDMAN = 4; + public static final int UI_TYPE_CREDENTIAL_MANAGER = 4; /** @hide */ @IntDef(prefix = { "UI_TYPE_" }, value = { diff --git a/services/core/java/com/android/server/notification/RateEstimator.java b/core/java/android/service/notification/RateEstimator.java index eda96ac84b16..04789c18ffe4 100644 --- a/services/core/java/com/android/server/notification/RateEstimator.java +++ b/core/java/android/service/notification/RateEstimator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 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. @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.server.notification; +package android.service.notification; /** @@ -22,7 +22,7 @@ package com.android.server.notification; * * {@hide} */ -class RateEstimator { +public class RateEstimator { private static final double RATE_ALPHA = 0.7; private static final double MINIMUM_DT = 0.0005; diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags index e209a286966a..5ba2baec6fcf 100644 --- a/core/java/android/speech/tts/EventLogTags.logtags +++ b/core/java/android/speech/tts/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.speech.tts; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index c9d560c3424b..1ea226b013d6 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -19,6 +19,7 @@ package android.view; import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE; import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS; import static android.hardware.flags.Flags.FLAG_OVERLAYPROPERTIES_CLASS_API; +import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUPPORTED_REFRESH_RATES; import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API; @@ -58,6 +59,7 @@ import android.os.SystemClock; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; +import android.util.TypedValue; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1048,6 +1050,19 @@ public final class Display { } /** + * Returns the smallest size of the display in dp + * @hide + */ + public float getMinSizeDimensionDp() { + synchronized (mLock) { + updateDisplayInfoLocked(); + mDisplayInfo.getAppMetrics(mTempMetrics); + return TypedValue.deriveDimension(COMPLEX_UNIT_DIP, + Math.min(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight), mTempMetrics); + } + } + + /** * @deprecated Use {@link WindowMetrics#getBounds#width()} instead. */ @Deprecated @@ -1301,17 +1316,23 @@ public final class Display { } /** - * Represents the {@link FrameRateCategory} for the Normal frame rate + * Normal category determines the framework's recommended normal frame rate. + * Opt for this normal rate unless a higher frame rate significantly enhances + * the user experience. * - * @see FrameRateCategory + * @see #getSuggestedFrameRate(int) + * @see #FRAME_RATE_CATEGORY_HIGH */ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE) public static final int FRAME_RATE_CATEGORY_NORMAL = 0; /** - * Represents the {@link FrameRateCategory} for the High frame rate + * High category determines the framework's recommended high frame rate. + * Opt for this high rate when a higher frame rate significantly enhances + * the user experience. * - * @see FrameRateCategory + * @see #getSuggestedFrameRate(int) + * @see #FRAME_RATE_CATEGORY_NORMAL */ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE) public static final int FRAME_RATE_CATEGORY_HIGH = 1; @@ -1332,22 +1353,17 @@ public final class Display { * * <p> For example, an animation that does not require fast render rates can use * the {@link #FRAME_RATE_CATEGORY_NORMAL} to get the suggested frame rate. - * The suggested frame rate then can be used in the - * {@link Surface.FrameRateParams.Builder#setDesiredRateRange} for desiredMinRate. * * <pre>{@code * float desiredMinRate = display.getSuggestedFrameRate(FRAME_RATE_CATEGORY_NORMAL); - * Surface.FrameRateParams params = new Surface.FrameRateParams.Builder(). - * setDesiredRateRange(desiredMinRate, Float.MAX).build(); - * surface.setFrameRate(params); + * surface.setFrameRate(desiredMinRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT); * }</pre> * </p> * * @param category either {@link #FRAME_RATE_CATEGORY_NORMAL} * or {@link #FRAME_RATE_CATEGORY_HIGH} * - * @see Surface#setFrameRate(Surface.FrameRateParams) - * @see SurfaceControl.Transaction#setFrameRate(SurfaceControl, Surface.FrameRateParams) + * @see Surface#setFrameRate(float, int) * @throws IllegalArgumentException when category is not {@link #FRAME_RATE_CATEGORY_NORMAL} * or {@link #FRAME_RATE_CATEGORY_HIGH} */ diff --git a/core/java/android/view/EventLogTags.logtags b/core/java/android/view/EventLogTags.logtags index f3792930647a..95894fa32d6b 100644 --- a/core/java/android/view/EventLogTags.logtags +++ b/core/java/android/view/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.view @@ -35,7 +35,7 @@ option java_package android.view # 6: Percent # Default value for data of type int/long is 2 (bytes). # -# See system/core/logcat/event.logtags for the master copy of the tags. +# See system/logging/logcat/event.logtags for the master copy of the tags. # 32000 - 32999 reserved for input method framework # IME animation is started. 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..d13f0e21bf80 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); @@ -28277,28 +28277,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= PFLAG_FORCE_LAYOUT; mPrivateFlags |= PFLAG_INVALIDATED; - if (mParent != null) { - if (!mParent.isLayoutRequested()) { - mParent.requestLayout(); - } else { - clearMeasureCacheOfAncestors(); - } + if (mParent != null && !mParent.isLayoutRequested()) { + mParent.requestLayout(); } if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { mAttachInfo.mViewRequestingLayout = null; } } - private void clearMeasureCacheOfAncestors() { - ViewParent parent = mParent; - while (parent instanceof View view) { - if (view.mMeasureCache != null) { - view.mMeasureCache.clear(); - } - parent = view.mParent; - } - } - /** * Forces this view to be laid out during the next layout pass. * This method does not call requestLayout() or forceLayout() @@ -28654,10 +28640,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @RemotableViewMethod public void setMinimumHeight(int minHeight) { - if (mMinHeight != minHeight) { - mMinHeight = minHeight; - requestLayout(); - } + mMinHeight = minHeight; + requestLayout(); } /** @@ -28687,10 +28671,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @RemotableViewMethod public void setMinimumWidth(int minWidth) { - if (mMinWidth != minWidth) { - mMinWidth = minWidth; - requestLayout(); - } + mMinWidth = minWidth; + requestLayout(); } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 63bf392b5ef1..9e97a8eb58aa 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -591,7 +591,7 @@ public class ViewConfiguration { res.getBoolean( com.android.internal.R.bool.config_viewBasedRotaryEncoderHapticsEnabled); mViewTouchScreenHapticScrollFeedbackEnabled = - Flags.enableTouchScrollFeedback() + Flags.enableScrollFeedbackForTouch() ? res.getBoolean( com.android.internal.R.bool .config_viewTouchScreenHapticScrollFeedbackEnabled) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1596b85bb461..c1b92ee3f74e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -17,6 +17,7 @@ package android.view; import static android.adpf.Flags.adpfViewrootimplActionDownBoost; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; @@ -7977,8 +7978,9 @@ public final class ViewRootImpl implements ViewParent, } private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { - if (getConfiguration().windowConfiguration.getWindowingMode() - != WINDOWING_MODE_MULTI_WINDOW) { + final int windowingMode = getConfiguration().windowConfiguration.getWindowingMode(); + if (windowingMode != WINDOWING_MODE_MULTI_WINDOW + && windowingMode != WINDOWING_MODE_FREEFORM) { return false; } try { diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 1be7f4849f07..43a946a234ba 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -87,8 +87,12 @@ public abstract class ViewStructure { * <p>This value is added to mainly help with debugging purpose. */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @SuppressWarnings( + "ActionValue") // Lint expects this as + // android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER + // but should not have contentcapture public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = - "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; + "android.view.extra.VIRTUAL_STRUCTURE_TYPE"; /** * Key used for specifying the version of the view that generated the virtual structure for @@ -98,8 +102,12 @@ public abstract class ViewStructure { * "104.0.5112.69", then the value should be "104.0.5112.69" */ @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @SuppressWarnings( + "ActionValue") // Lint expects this as + // android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE + // but should not have contentcapture public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = - "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; + "android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; /** * Set the identifier for this view. 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/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig index ebda4d472b0d..ddf6ff11a83a 100644 --- a/core/java/android/view/flags/scroll_feedback_flags.aconfig +++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig @@ -17,10 +17,10 @@ flag { } flag { - namespace: "toolkit" - name: "enable_touch_scroll_feedback" + namespace: "wear_frameworks" + name: "enable_scroll_feedback_for_touch" description: "Enables touchscreen haptic scroll feedback" - bug: "331830899" + bug: "382135785" is_fixed_read_only: true } diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 6d89f3d89077..f82e5f984f5d 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -948,7 +948,7 @@ public final class InputMethodManager { // requestedVisibleTypes of WindowInsetsController by hiding the IME final var statsToken = ImeTracker.forLogging().onStart( ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT, - SoftInputShowHideReason.REASON_HIDE_WINDOW_LOST_FOCUS, + SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS, false /* fromUser */); if (DEBUG) { Log.d(TAG, "onWindowLostFocus, hiding IME because " 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/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags index a90aebd71716..8bbd5a9d0246 100644 --- a/core/java/android/webkit/EventLogTags.logtags +++ b/core/java/android/webkit/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package android.webkit; diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 3c854ea4fad4..fc3014a0eaec 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -16,7 +16,7 @@ package android.widget; -import static android.view.flags.Flags.enableTouchScrollFeedback; +import static android.view.flags.Flags.enableScrollFeedbackForTouch; import static android.view.flags.Flags.scrollFeedbackApi; import static android.view.flags.Flags.viewVelocityApi; @@ -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 (enableTouchScrollFeedback()) { + 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 (enableTouchScrollFeedback()) { + if (vtev != null && enableScrollFeedbackForTouch()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit( vtev.getDeviceId(), vtev.getSource(), diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 2cd390113040..9fe3fd6ddc1a 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -20,6 +20,7 @@ import static android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL; import static android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO; import static android.appwidget.flags.Flags.drawDataParcel; import static android.appwidget.flags.Flags.remoteAdapterConversion; +import static android.content.res.Flags.FLAG_SELF_TARGETING_ANDROID_RESOURCE_FRRO; import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; import static android.util.proto.ProtoInputStream.NO_MORE_FIELDS; import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; @@ -47,6 +48,7 @@ import android.app.LoadedApk; import android.app.PendingIntent; import android.app.RemoteInput; import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetManager.ServiceCollectionCache; import android.appwidget.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -54,7 +56,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentSender; -import android.content.ServiceConnection; import android.content.om.FabricatedOverlay; import android.content.om.OverlayInfo; import android.content.om.OverlayManager; @@ -82,7 +83,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; -import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -127,8 +127,8 @@ import android.widget.CompoundButton.OnCheckedChangeListener; import com.android.internal.R; import com.android.internal.util.Preconditions; import com.android.internal.widget.IRemoteViewsFactory; -import com.android.internal.widget.remotecompose.core.operations.Theme; import com.android.internal.widget.remotecompose.core.CoreDocument; +import com.android.internal.widget.remotecompose.core.operations.Theme; import com.android.internal.widget.remotecompose.player.RemoteComposeDocument; import com.android.internal.widget.remotecompose.player.RemoteComposePlayer; @@ -1391,8 +1391,10 @@ public class RemoteViews implements Parcelable, Filter { /** * @hide */ - public CompletableFuture<Void> collectAllIntents(int bitmapSizeLimit) { - return mCollectionCache.collectAllIntentsNoComplete(this, bitmapSizeLimit); + public CompletableFuture<Void> collectAllIntents(int bitmapSizeLimit, + @NonNull ServiceCollectionCache collectionCache) { + return mCollectionCache.collectAllIntentsNoComplete(this, bitmapSizeLimit, + collectionCache); } private class RemoteCollectionCache { @@ -1446,7 +1448,8 @@ public class RemoteViews implements Parcelable, Filter { } public @NonNull CompletableFuture<Void> collectAllIntentsNoComplete( - @NonNull RemoteViews inViews, int bitmapSizeLimit) { + @NonNull RemoteViews inViews, int bitmapSizeLimit, + @NonNull ServiceCollectionCache collectionCache) { SparseArray<Intent> idToIntentMapping = new SparseArray<>(); // Collect the number of uinque Intent (which is equal to the number of new connections // to make) for size allocation and exclude certain collections from being written to @@ -1478,7 +1481,7 @@ public class RemoteViews implements Parcelable, Filter { / numOfIntents; return connectAllUniqueIntents(individualSize, individualBitmapSizeLimit, - idToIntentMapping); + idToIntentMapping, collectionCache); } private void collectAllIntentsInternal(@NonNull RemoteViews inViews, @@ -1544,13 +1547,14 @@ public class RemoteViews implements Parcelable, Filter { } private @NonNull CompletableFuture<Void> connectAllUniqueIntents(int individualSize, - int individualBitmapSize, @NonNull SparseArray<Intent> idToIntentMapping) { + int individualBitmapSize, @NonNull SparseArray<Intent> idToIntentMapping, + @NonNull ServiceCollectionCache collectionCache) { List<CompletableFuture<Void>> intentFutureList = new ArrayList<>(); for (int i = 0; i < idToIntentMapping.size(); i++) { String currentIntentUri = mIdToUriMapping.get(idToIntentMapping.keyAt(i)); Intent currentIntent = idToIntentMapping.valueAt(i); intentFutureList.add(getItemsFutureFromIntentWithTimeout(currentIntent, - individualSize, individualBitmapSize) + individualSize, individualBitmapSize, collectionCache) .thenAccept(items -> { items.setHierarchyRootData(getHierarchyRootData()); mUriToCollectionMapping.put(currentIntentUri, items); @@ -1561,7 +1565,8 @@ public class RemoteViews implements Parcelable, Filter { } private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout( - Intent intent, int individualSize, int individualBitmapSize) { + Intent intent, int individualSize, int individualBitmapSize, + @NonNull ServiceCollectionCache collectionCache) { if (intent == null) { Log.e(LOG_TAG, "Null intent received when generating adapter future"); return CompletableFuture.completedFuture(new RemoteCollectionItems @@ -1581,39 +1586,24 @@ public class RemoteViews implements Parcelable, Filter { return result; } - context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE), - result.defaultExecutor(), new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName componentName, - IBinder iBinder) { - RemoteCollectionItems items; - try { - items = IRemoteViewsFactory.Stub.asInterface(iBinder) - .getRemoteCollectionItems(individualSize, - individualBitmapSize); - } catch (RemoteException re) { - items = new RemoteCollectionItems.Builder().build(); - Log.e(LOG_TAG, "Error getting collection items from the" - + " factory", re); - } finally { - context.unbindService(this); - } - - if (items == null) { - items = new RemoteCollectionItems.Builder().build(); - } - - result.complete(items); - } + collectionCache.connectAndConsume(intent, iBinder -> { + RemoteCollectionItems items; + try { + items = IRemoteViewsFactory.Stub.asInterface(iBinder) + .getRemoteCollectionItems(individualSize, + individualBitmapSize); + } catch (RemoteException re) { + items = new RemoteCollectionItems.Builder().build(); + Log.e(LOG_TAG, "Error getting collection items from the" + + " factory", re); + } - @Override - public void onNullBinding(ComponentName name) { - context.unbindService(this); - } + if (items == null) { + items = new RemoteCollectionItems.Builder().build(); + } - @Override - public void onServiceDisconnected(ComponentName componentName) { } - }); + result.complete(items); + }, result.defaultExecutor()); result.completeOnTimeout( new RemoteCollectionItems.Builder().build(), @@ -8709,6 +8699,7 @@ public class RemoteViews implements Parcelable, Filter { * * @hide */ + @FlaggedApi(FLAG_SELF_TARGETING_ANDROID_RESOURCE_FRRO) @Nullable public static ColorResources createWithOverlay(Context context, SparseIntArray colorMapping) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 511c832a4876..184933fb8288 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -16,7 +16,7 @@ package android.widget; -import static android.view.flags.Flags.enableTouchScrollFeedback; +import static android.view.flags.Flags.enableScrollFeedbackForTouch; import static android.view.flags.Flags.viewVelocityApi; import android.annotation.ColorInt; @@ -909,7 +909,7 @@ public class ScrollView extends FrameLayout { } // TODO: b/360198915 - Add unit tests. - if (enableTouchScrollFeedback()) { + if (enableScrollFeedbackForTouch()) { if (hitTopLimit || hitBottomLimit) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit(vtev.getDeviceId(), 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/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index a88a17283482..c8001198bdf6 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -486,7 +486,7 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Sets to containers adjacent to each other. Containers below two visible adjacent roots will + * Sets two containers adjacent to each other. Containers below two visible adjacent roots will * be made invisible. This currently only applies to TaskFragment containers created by * organizer. * @param root1 the first root. @@ -495,9 +495,64 @@ public final class WindowContainerTransaction implements Parcelable { @NonNull public WindowContainerTransaction setAdjacentRoots( @NonNull WindowContainerToken root1, @NonNull WindowContainerToken root2) { - mHierarchyOps.add(HierarchyOp.createForAdjacentRoots( - root1.asBinder(), - root2.asBinder())); + if (!Flags.allowMultipleAdjacentTaskFragments()) { + mHierarchyOps.add(HierarchyOp.createForAdjacentRoots( + root1.asBinder(), + root2.asBinder())); + return this; + } + return setAdjacentRootSet(root1, root2); + } + + /** + * Sets multiple containers adjacent to each other. Containers below the visible adjacent roots + * will be made invisible. This currently only applies to Task containers created by organizer. + * + * To remove one container from the adjacent roots, one can call {@link #clearAdjacentRoots} + * with the target container. + * To remove all containers from the adjacent roots, one much call {@link #clearAdjacentRoots} + * on each container if there were more than two containers in the set. + * + * For non-Task TaskFragment, use {@link #setAdjacentTaskFragments} instead. + * + * @param roots the Tasks that should be adjacent to each other. + * @throws IllegalArgumentException if roots have size < 2. + * @hide // TODO(b/373709676) Rename to setAdjacentRoots and update CTS. + */ + @NonNull + public WindowContainerTransaction setAdjacentRootSet( + @NonNull WindowContainerToken... roots) { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + throw new IllegalArgumentException("allowMultipleAdjacentTaskFragments is not enabled." + + " Use #setAdjacentRoots instead."); + } + if (roots.length < 2) { + throw new IllegalArgumentException("setAdjacentRootSet must have size >= 2"); + } + final IBinder[] rootTokens = new IBinder[roots.length]; + for (int i = 0; i < roots.length; i++) { + rootTokens[i] = roots[i].asBinder(); + } + mHierarchyOps.add( + new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS) + .setContainers(rootTokens) + .build()); + return this; + } + + /** + * Clears container adjacent. + * If {@link #setAdjacentRootSet} is called with more than 2 roots, calling this will only + * remove the given root from the adjacent set. The rest of roots will stay adjacent to each + * other. + * + * @param root the root container to clear the adjacent roots for. + * @hide + */ + @NonNull + public WindowContainerTransaction clearAdjacentRoots( + @NonNull WindowContainerToken root) { + mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder())); return this; } @@ -967,18 +1022,6 @@ public final class WindowContainerTransaction implements Parcelable { } /** - * Clears container adjacent. - * @param root the root container to clear the adjacent roots for. - * @hide - */ - @NonNull - public WindowContainerTransaction clearAdjacentRoots( - @NonNull WindowContainerToken root) { - mHierarchyOps.add(HierarchyOp.createForClearAdjacentRoots(root.asBinder())); - return this; - } - - /** * Sets/removes the reparent leaf task flag for this {@code windowContainer}. * When this is set, the server side will try to reparent the leaf task to task display area * if there is an existing activity in history during the activity launch. This operation only @@ -1520,6 +1563,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private IBinder mContainer; + @Nullable + private IBinder[] mContainers; + // If this is same as mContainer, then only change position, don't reparent. @Nullable private IBinder mReparent; @@ -1704,6 +1750,7 @@ public final class WindowContainerTransaction implements Parcelable { public HierarchyOp(@NonNull HierarchyOp copy) { mType = copy.mType; mContainer = copy.mContainer; + mContainers = copy.mContainers; mBounds = copy.mBounds; mIncludingParents = copy.mIncludingParents; mReparent = copy.mReparent; @@ -1729,6 +1776,7 @@ public final class WindowContainerTransaction implements Parcelable { protected HierarchyOp(Parcel in) { mType = in.readInt(); mContainer = in.readStrongBinder(); + mContainers = in.createBinderArray(); mBounds = in.readTypedObject(Rect.CREATOR); mIncludingParents = in.readBoolean(); mReparent = in.readStrongBinder(); @@ -1780,6 +1828,13 @@ public final class WindowContainerTransaction implements Parcelable { } @NonNull + public IBinder[] getContainers() { + return mContainers; + } + + /** @deprecated b/373709676 replace with {@link #getContainers()}. */ + @Deprecated + @NonNull public IBinder getAdjacentRoot() { return mReparent; } @@ -1869,7 +1924,7 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_REORDER: return "reorder"; case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: return "childrenTasksReparent"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: return "setLaunchRoot"; - case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoot"; + case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "setAdjacentRoots"; case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "launchTask"; case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "setAdjacentFlagRoot"; case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT: @@ -1883,7 +1938,7 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop"; case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask"; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity"; - case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoot"; + case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoots"; case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: return "setReparentLeafTaskIfRelaunch"; case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: @@ -1923,8 +1978,18 @@ public final class WindowContainerTransaction implements Parcelable { sb.append(mContainer).append(" to ").append(mToTop ? "top" : "bottom"); break; case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: - sb.append("container=").append(mContainer) - .append(" adjacentRoot=").append(mReparent); + if (Flags.allowMultipleAdjacentTaskFragments()) { + for (IBinder container : mContainers) { + if (container == mContainers[0]) { + sb.append("adjacentRoots=").append(container); + } else { + sb.append(", ").append(container); + } + } + } else { + sb.append("container=").append(mContainer) + .append(" adjacentRoot=").append(mReparent); + } break; case HIERARCHY_OP_TYPE_LAUNCH_TASK: sb.append(mLaunchOptions); @@ -1997,6 +2062,7 @@ public final class WindowContainerTransaction implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); dest.writeStrongBinder(mContainer); + dest.writeBinderArray(mContainers); dest.writeTypedObject(mBounds, flags); dest.writeBoolean(mIncludingParents); dest.writeStrongBinder(mReparent); @@ -2044,6 +2110,9 @@ public final class WindowContainerTransaction implements Parcelable { private IBinder mContainer; @Nullable + private IBinder[] mContainers; + + @Nullable private IBinder mReparent; @Nullable @@ -2104,6 +2173,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setContainers(@Nullable IBinder[] containers) { + mContainers = containers; + return this; + } + Builder setReparentContainer(@Nullable IBinder reparentContainer) { mReparent = reparentContainer; return this; @@ -2209,6 +2283,7 @@ public final class WindowContainerTransaction implements Parcelable { HierarchyOp build() { final HierarchyOp hierarchyOp = new HierarchyOp(mType); hierarchyOp.mContainer = mContainer; + hierarchyOp.mContainers = mContainers; hierarchyOp.mReparent = mReparent; hierarchyOp.mWindowingModes = mWindowingModes != null ? Arrays.copyOf(mWindowingModes, mWindowingModes.length) 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/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 8ebc1ed5ae0a..6caa20e29c17 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -414,6 +414,16 @@ flag { } flag { + name: "enable_desktop_recents_transitions_corners_bugfix" + namespace: "lse_desktop_experience" + description: "Enables rounded corners bugfix for Recents transitions." + bug: "383079261" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_move_to_next_display_shortcut" namespace: "lse_desktop_experience" description: "Add new keyboard shortcut of moving a task into next display" @@ -449,6 +459,14 @@ flag { } flag { + name: "reparent_window_token_api" + namespace: "lse_desktop_experience" + description: "Allows to reparent a window token to a different display" + is_fixed_read_only: true + bug: "381258683" +} + +flag { name: "enable_desktop_windowing_hsum" namespace: "lse_desktop_experience" description: "Enables HSUM on desktop mode." @@ -481,4 +499,22 @@ flag { namespace: "lse_desktop_experience" description: "Bugfixes / papercuts to bring Desktop Windowing to secondary displays." bug: "382023296" +} + +flag { + name: "enable_top_visible_root_task_per_user_tracking" + namespace: "lse_desktop_experience" + description: "Enables tracking the top visible root tasks for a user." + bug: "381038076" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_per_display_desktop_wallpaper_activity" + namespace: "lse_desktop_experience" + description: "Enables having a DesktopWallpaperActivity at a per-display level." + bug: "381935663" }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 30f0c7371270..1c27515b06f0 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -455,6 +455,17 @@ flag { } flag { + name: "remove_defer_hiding_client" + namespace: "windowing_frontend" + description: "Remove mDeferHidingClient since everything is in shell-transition." + is_fixed_read_only: true + bug: "382485959" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "relative_insets" namespace: "windowing_frontend" description: "Support insets definition and calculation relative to task bounds." diff --git a/core/java/com/android/internal/app/EventLogTags.logtags b/core/java/com/android/internal/app/EventLogTags.logtags index d681a8d26e8e..a18a8243305b 100644 --- a/core/java/com/android/internal/app/EventLogTags.logtags +++ b/core/java/com/android/internal/app/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.internal.app; 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/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java index fa5cf2a396b9..5d4e6a083af4 100644 --- a/core/java/com/android/internal/content/om/OverlayManagerImpl.java +++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java @@ -36,6 +36,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.parsing.FrameworkParsingPackageUtils; import android.content.res.AssetManager; +import android.content.res.Flags; import android.os.FabricatedOverlayInfo; import android.os.FabricatedOverlayInternal; import android.os.FabricatedOverlayInternalEntry; @@ -235,17 +236,24 @@ public class OverlayManagerImpl { Preconditions.checkArgument(!entryList.isEmpty(), "overlay entries shouldn't be empty"); final String overlayName = checkOverlayNameValid(overlayInternal.overlayName); checkPackageName(overlayInternal.packageName); - Preconditions.checkStringNotEmpty(overlayInternal.targetPackageName); + if (Flags.selfTargetingAndroidResourceFrro()) { + Preconditions.checkStringNotEmpty(overlayInternal.targetPackageName); + } else { + checkPackageName(overlayInternal.targetPackageName); + Preconditions.checkStringNotEmpty( + overlayInternal.targetOverlayable, + "Target overlayable should be neither null nor empty string."); + } final ApplicationInfo applicationInfo = mContext.getApplicationInfo(); String targetPackage = null; - if (TextUtils.equals(overlayInternal.targetPackageName, "android")) { + if (Flags.selfTargetingAndroidResourceFrro() && TextUtils.equals( + overlayInternal.targetPackageName, "android")) { targetPackage = AssetManager.FRAMEWORK_APK_PATH; } else { targetPackage = Preconditions.checkStringNotEmpty( applicationInfo.getBaseCodePath()); } - final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION); final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION); diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index 2a5593f6d584..4d5e67ab8fde 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -299,6 +299,12 @@ public final class InputMethodDebug { return "SHOW_SOFT_INPUT_IMM_DEPRECATION"; case SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION: return "CONTROL_WINDOW_INSETS_ANIMATION"; + case SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED: + return "SHOW_INPUT_TARGET_CHANGED"; + case SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED: + return "HIDE_INPUT_TARGET_CHANGED"; + case SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS: + return "HIDE_WINDOW_LOST_FOCUS"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index 592ea9e5e600..cf0580c2f021 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -91,7 +91,7 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.CONTROL_WINDOW_INSETS_ANIMATION, SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED, SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED, - SoftInputShowHideReason.REASON_HIDE_WINDOW_LOST_FOCUS, + SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS, }) public @interface SoftInputShowHideReason { /** Default, undefined reason. */ @@ -340,18 +340,6 @@ public @interface SoftInputShowHideReason { int HIDE_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_WINDOW_LEGACY_DIRECT; /** - * Show soft input because the input target changed - * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}. - */ - int SHOW_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_SHOW_INPUT_TARGET_CHANGED; - - /** - * Hide soft input because the input target changed by - * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}. - */ - int HIDE_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_HIDE_INPUT_TARGET_CHANGED; - - /** * Show / Hide soft input by * {@link android.inputmethodservice.InputMethodService#resetStateForNewConfiguration}. */ @@ -420,6 +408,18 @@ public @interface SoftInputShowHideReason { */ int CONTROL_WINDOW_INSETS_ANIMATION = ImeProtoEnums.REASON_CONTROL_WINDOW_INSETS_ANIMATION; + /** + * Show soft input because the input target changed + * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}. + */ + int SHOW_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_SHOW_INPUT_TARGET_CHANGED; + + /** + * Hide soft input because the input target changed by + * {@link com.android.server.wm.ImeInsetsSourceProvider#onInputTargetChanged}. + */ + int HIDE_INPUT_TARGET_CHANGED = ImeProtoEnums.REASON_HIDE_INPUT_TARGET_CHANGED; + /** Hide soft input when the window lost focus. */ - int REASON_HIDE_WINDOW_LOST_FOCUS = ImeProtoEnums.REASON_HIDE_WINDOW_LOST_FOCUS; + int HIDE_WINDOW_LOST_FOCUS = ImeProtoEnums.REASON_HIDE_WINDOW_LOST_FOCUS; } diff --git a/core/java/com/android/internal/jank/EventLogTags.logtags b/core/java/com/android/internal/jank/EventLogTags.logtags index 66ee131badac..dfec49907c69 100644 --- a/core/java/com/android/internal/jank/EventLogTags.logtags +++ b/core/java/com/android/internal/jank/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.internal.jank; diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags index 693bd16e6170..db47797cb03d 100644 --- a/core/java/com/android/internal/logging/EventLogTags.logtags +++ b/core/java/com/android/internal/logging/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.internal.logging; 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/CallLayout.java b/core/java/com/android/internal/widget/CallLayout.java index c85257578492..3a7c75afdd14 100644 --- a/core/java/com/android/internal/widget/CallLayout.java +++ b/core/java/com/android/internal/widget/CallLayout.java @@ -30,7 +30,6 @@ import android.util.AttributeSet; import android.view.RemotableViewMethod; import android.widget.FrameLayout; import android.widget.RemoteViews; -import android.widget.TextView; import android.widget.flags.Flags; import com.android.internal.R; @@ -59,7 +58,6 @@ public class CallLayout extends FrameLayout { private CachingIconView mConversationIconView; private CachingIconView mIcon; private CachingIconView mConversationIconBadgeBg; - private TextView mConversationText; public CallLayout(@NonNull Context context) { super(context); @@ -83,7 +81,6 @@ public class CallLayout extends FrameLayout { protected void onFinishInflate() { super.onFinishInflate(); mPeopleHelper.init(getContext()); - mConversationText = findViewById(R.id.conversation_text); mConversationIconView = findViewById(R.id.conversation_icon); mIcon = findViewById(R.id.icon); mConversationIconBadgeBg = findViewById(R.id.conversation_icon_badge_bg); diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 4b90420a75ee..b3ab5d3cd258 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -777,37 +777,40 @@ public class ConversationLayout extends FrameLayout } - int conversationAvatarSize; - int facepileAvatarSize; - int facePileBackgroundSize; - if (mIsCollapsed) { - conversationAvatarSize = mConversationAvatarSize; - facepileAvatarSize = mFacePileAvatarSize; - facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth; - } else { - conversationAvatarSize = mConversationAvatarSizeExpanded; - facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; - facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; - } - LayoutParams layoutParams = (LayoutParams) mConversationFacePile.getLayoutParams(); - layoutParams.width = conversationAvatarSize; - layoutParams.height = conversationAvatarSize; - mConversationFacePile.setLayoutParams(layoutParams); + if (!notificationsRedesignTemplates()) { + // We no longer need to update the size based on expansion state. + int conversationAvatarSize; + int facepileAvatarSize; + int facePileBackgroundSize; + if (mIsCollapsed) { + conversationAvatarSize = mConversationAvatarSize; + facepileAvatarSize = mFacePileAvatarSize; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidth; + } else { + conversationAvatarSize = mConversationAvatarSizeExpanded; + facepileAvatarSize = mFacePileAvatarSizeExpandedGroup; + facePileBackgroundSize = facepileAvatarSize + 2 * mFacePileProtectionWidthExpanded; + } + LayoutParams layoutParams = (LayoutParams) mConversationFacePile.getLayoutParams(); + layoutParams.width = conversationAvatarSize; + layoutParams.height = conversationAvatarSize; + mConversationFacePile.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) bottomView.getLayoutParams(); - layoutParams.width = facepileAvatarSize; - layoutParams.height = facepileAvatarSize; - bottomView.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) bottomView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + bottomView.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) topView.getLayoutParams(); - layoutParams.width = facepileAvatarSize; - layoutParams.height = facepileAvatarSize; - topView.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) topView.getLayoutParams(); + layoutParams.width = facepileAvatarSize; + layoutParams.height = facepileAvatarSize; + topView.setLayoutParams(layoutParams); - layoutParams = (LayoutParams) bottomBackground.getLayoutParams(); - layoutParams.width = facePileBackgroundSize; - layoutParams.height = facePileBackgroundSize; - bottomBackground.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) bottomBackground.getLayoutParams(); + layoutParams.width = facePileBackgroundSize; + layoutParams.height = facePileBackgroundSize; + bottomBackground.setLayoutParams(layoutParams); + } } /** @@ -832,6 +835,11 @@ public class ConversationLayout extends FrameLayout * update the icon position and sizing */ private void updateIconPositionAndSize() { + if (notificationsRedesignTemplates()) { + // Icon size is fixed in the redesign. + return; + } + int badgeProtrusion; int conversationAvatarSize; if (mIsOneToOne || mIsCollapsed) { @@ -864,6 +872,11 @@ public class ConversationLayout extends FrameLayout } private void updatePaddingsBasedOnContentAvailability() { + if (notificationsRedesignTemplates()) { + // group icons have the same size as 1:1 conversations + return; + } + // groups have avatars that need more spacing mMessagingLinearLayout.setSpacing( mIsOneToOne ? mMessageSpacingStandard : mMessageSpacingGroup); 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/java/org/chromium/arc/EventLogTags.logtags b/core/java/org/chromium/arc/EventLogTags.logtags index 1b7160e90224..8102d6f10ed4 100644 --- a/core/java/org/chromium/arc/EventLogTags.logtags +++ b/core/java/org/chromium/arc/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package org.chromium.arc diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 8e3303a4ddbd..027113a75f6b 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -92,7 +92,6 @@ cc_library_shared_for_libandroid_runtime { "android_view_VelocityTracker.cpp", "android_view_VerifiedKeyEvent.cpp", "android_view_VerifiedMotionEvent.cpp", - "com_android_internal_util_ArrayUtils.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", "core_jni_helpers.cpp", ":deviceproductinfoconstants_aidl", @@ -264,6 +263,7 @@ cc_library_shared_for_libandroid_runtime { "com_android_internal_os_ZygoteCommandBuffer.cpp", "com_android_internal_os_ZygoteInit.cpp", "com_android_internal_security_VerityUtils.cpp", + "com_android_internal_util_ArrayUtils.cpp", "hwbinder/EphemeralStorage.cpp", "fd_utils.cpp", "android_hardware_input_InputWindowHandle.cpp", diff --git a/core/jni/android_app_PropertyInvalidatedCache.cpp b/core/jni/android_app_PropertyInvalidatedCache.cpp index ead66660a0a4..12585d5f8137 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.cpp +++ b/core/jni/android_app_PropertyInvalidatedCache.cpp @@ -28,24 +28,77 @@ #include "core_jni_helpers.h" #include "android_app_PropertyInvalidatedCache.h" +namespace android::app::PropertyInvalidatedCache { + +// These provide run-time access to the sizing parameters. +int NonceStore::getMaxNonce() const { + return kMaxNonce; +} + +size_t NonceStore::getMaxByte() const { + return kMaxByte; +} + +// Fetch a nonce, returning UNSET if the index is out of range. This method specifically +// does not throw or generate an error if the index is out of range; this allows the method +// to be called in a CriticalNative JNI API. +int64_t NonceStore::getNonce(int index) const { + if (index < 0 || index >= kMaxNonce) { + return UNSET; + } else { + return nonce()[index]; + } +} + +// Set a nonce and return true. Return false if the index is out of range. This method +// specifically does not throw or generate an error if the index is out of range; this +// allows the method to be called in a CriticalNative JNI API. +bool NonceStore::setNonce(int index, int64_t value) { + if (index < 0 || index >= kMaxNonce) { + return false; + } else { + nonce()[index] = value; + return true; + } +} + +// Fetch just the byte-block hash +int32_t NonceStore::getHash() const { + return mByteHash; +} + +// Copy the byte block to the target and return the current hash. +int32_t NonceStore::getByteBlock(block_t* block, size_t len) const { + memcpy(block, (void*) byteBlock(), std::min(kMaxByte, len)); + return mByteHash; +} + +// Set the byte block and the hash. +void NonceStore::setByteBlock(int hash, const block_t* block, size_t len) { + memcpy((void*) byteBlock(), block, len = std::min(kMaxByte, len)); + mByteHash = hash; +} + +} // namespace android::app::PropertyInvalidatedCache; + namespace { using namespace android::app::PropertyInvalidatedCache; // Convert a jlong to a nonce block. This is a convenience function that should be inlined by // the compiler. -inline SystemCacheNonce* sysCache(jlong ptr) { - return reinterpret_cast<SystemCacheNonce*>(ptr); +inline NonceStore* nonceCache(jlong ptr) { + return reinterpret_cast<NonceStore*>(ptr); } // Return the number of nonces in the nonce block. jint getMaxNonce(JNIEnv*, jclass, jlong ptr) { - return sysCache(ptr)->getMaxNonce(); + return nonceCache(ptr)->getMaxNonce(); } // Return the number of string bytes in the nonce block. jint getMaxByte(JNIEnv*, jclass, jlong ptr) { - return sysCache(ptr)->getMaxByte(); + return nonceCache(ptr)->getMaxByte(); } // Set the byte block. The first int is the hash to set and the second is the array to copy. @@ -56,25 +109,25 @@ void setByteBlock(JNIEnv* env, jclass, jlong ptr, jint hash, jbyteArray val) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "null byte block"); return; } - sysCache(ptr)->setByteBlock(hash, value.get(), value.size()); + nonceCache(ptr)->setByteBlock(hash, value.get(), value.size()); } // Fetch the byte block. If the incoming hash is the same as the local hash, the Java layer is // presumed to have an up-to-date copy of the byte block; do not copy byte array. The local // hash is returned. jint getByteBlock(JNIEnv* env, jclass, jlong ptr, jint hash, jbyteArray val) { - if (sysCache(ptr)->getHash() == hash) { + if (nonceCache(ptr)->getHash() == hash) { return hash; } ScopedByteArrayRW value(env, val); - return sysCache(ptr)->getByteBlock(value.get(), value.size()); + return nonceCache(ptr)->getByteBlock(value.get(), value.size()); } // Fetch the byte block hash. // // This is a CriticalNative method and therefore does not get the JNIEnv or jclass parameters. jint getByteBlockHash(jlong ptr) { - return sysCache(ptr)->getHash(); + return nonceCache(ptr)->getHash(); } // Get a nonce value. So that this method can be CriticalNative, it returns 0 if the value is @@ -83,7 +136,7 @@ jint getByteBlockHash(jlong ptr) { // // This method is @CriticalNative and does not take a JNIEnv* or jclass argument. jlong getNonce(jlong ptr, jint index) { - return sysCache(ptr)->getNonce(index); + return nonceCache(ptr)->getNonce(index); } // Set a nonce value. So that this method can be CriticalNative, it returns a boolean: false if @@ -92,7 +145,7 @@ jlong getNonce(jlong ptr, jint index) { // // This method is @CriticalNative and does not take a JNIEnv* or jclass argument. jboolean setNonce(jlong ptr, jint index, jlong value) { - return sysCache(ptr)->setNonce(index, value); + return nonceCache(ptr)->setNonce(index, value); } static const JNINativeMethod gMethods[] = { diff --git a/core/jni/android_app_PropertyInvalidatedCache.h b/core/jni/android_app_PropertyInvalidatedCache.h index eefa8fa88624..00aa281b572f 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.h +++ b/core/jni/android_app_PropertyInvalidatedCache.h @@ -18,129 +18,139 @@ #include <memory.h> #include <atomic> +#include <cstdint> -namespace android { -namespace app { -namespace PropertyInvalidatedCache { +namespace android::app::PropertyInvalidatedCache { /** - * A cache nonce block contains an array of std::atomic<int64_t> and an array of bytes. The - * byte array has an associated hash. This class provides methods to read and write the fields - * of the block but it does not interpret the fields. - * - * On initialization, all fields are set to zero. - * - * In general, methods do not report errors. This allows the methods to be used in - * CriticalNative JNI APIs. - * - * The template is parameterized by the number of nonces it supports and the number of bytes in - * the string block. + * A head of a CacheNonce object. This contains all the fields that have a fixed size and + * location. Fields with a variable location are found via offsets. The offsets make this + * object position-independent, which is required because it is in shared memory and would be + * mapped into different virtual addresses for different processes. */ -template<int maxNonce, size_t maxByte> class CacheNonce { - - // The value of an unset field. - static const int UNSET = 0; - +class NonceStore { + protected: // A convenient typedef. The jbyteArray element type is jbyte, which the compiler treats as // signed char. typedef signed char block_t; - // The array of nonces - volatile std::atomic<int64_t> mNonce[maxNonce]; + // The nonce type. + typedef std::atomic<int64_t> nonce_t; - // The byte array. This is not atomic but it is guarded by the mByteHash. - volatile block_t mByteBlock[maxByte]; + // Atomics should be safe to use across processes if they are lock free. + static_assert(nonce_t::is_always_lock_free == true); - // The hash that validates the byte block - volatile std::atomic<int32_t> mByteHash; + // The value of an unset field. + static constexpr int UNSET = 0; - // Pad the class to a multiple of 8 bytes. - int32_t _pad; + // The size of the nonce array. + const int32_t kMaxNonce; - public: + // The size of the byte array. + const size_t kMaxByte; - // The expected size of this instance. This is a compile-time constant and can be used in a - // static assertion. - static const int expectedSize = - maxNonce * sizeof(std::atomic<int64_t>) - + sizeof(std::atomic<int32_t>) - + maxByte * sizeof(block_t) - + sizeof(int32_t); + // The offset to the nonce array. + const size_t mNonceOffset; - // These provide run-time access to the sizing parameters. - int getMaxNonce() const { - return maxNonce; - } + // The offset to the byte array. + const size_t mByteOffset; - size_t getMaxByte() const { - return maxByte; - } + // The byte block hash. This is fixed and at a known offset, so leave it in the base class. + volatile std::atomic<int32_t> mByteHash; - // Construct and initialize the memory. - CacheNonce() { - for (int i = 0; i < maxNonce; i++) { - mNonce[i] = UNSET; - } - mByteHash = UNSET; - memset((void*) mByteBlock, UNSET, sizeof(mByteBlock)); + // The constructor is protected! It only makes sense when called from a subclass. + NonceStore(int kMaxNonce, size_t kMaxByte, volatile nonce_t* nonce, volatile block_t* block) : + kMaxNonce(kMaxNonce), + kMaxByte(kMaxByte), + mNonceOffset(offset(this, const_cast<nonce_t*>(nonce))), + mByteOffset(offset(this, const_cast<block_t*>(block))) { } + public: + + // These provide run-time access to the sizing parameters. + int getMaxNonce() const; + size_t getMaxByte() const; + // Fetch a nonce, returning UNSET if the index is out of range. This method specifically // does not throw or generate an error if the index is out of range; this allows the method // to be called in a CriticalNative JNI API. - int64_t getNonce(int index) const { - if (index < 0 || index >= maxNonce) { - return UNSET; - } else { - return mNonce[index]; - } - } + int64_t getNonce(int index) const; // Set a nonce and return true. Return false if the index is out of range. This method // specifically does not throw or generate an error if the index is out of range; this // allows the method to be called in a CriticalNative JNI API. - bool setNonce(int index, int64_t value) { - if (index < 0 || index >= maxNonce) { - return false; - } else { - mNonce[index] = value; - return true; - } - } + bool setNonce(int index, int64_t value); // Fetch just the byte-block hash - int32_t getHash() const { - return mByteHash; - } + int32_t getHash() const; // Copy the byte block to the target and return the current hash. - int32_t getByteBlock(block_t* block, size_t len) const { - memcpy(block, (void*) mByteBlock, std::min(maxByte, len)); - return mByteHash; - } + int32_t getByteBlock(block_t* block, size_t len) const; // Set the byte block and the hash. - void setByteBlock(int hash, const block_t* block, size_t len) { - memcpy((void*) mByteBlock, block, len = std::min(maxByte, len)); - mByteHash = hash; + void setByteBlock(int hash, const block_t* block, size_t len); + + private: + + // A convenience function to compute the offset between two unlike pointers. + static size_t offset(void const* base, void const* member) { + return reinterpret_cast<uintptr_t>(member) - reinterpret_cast<std::uintptr_t>(base); + } + + // Return the address of the nonce array. + volatile nonce_t* nonce() const { + // The array is located at an offset from <this>. + return reinterpret_cast<nonce_t*>( + reinterpret_cast<std::uintptr_t>(this) + mNonceOffset); + } + + // Return the address of the byte block array. + volatile block_t* byteBlock() const { + // The array is located at an offset from <this>. + return reinterpret_cast<block_t*>( + reinterpret_cast<std::uintptr_t>(this) + mByteOffset); } }; /** - * Sizing parameters for the system_server PropertyInvalidatedCache support. A client can - * retrieve the values through the accessors in CacheNonce instances. + * A cache nonce block contains an array of std::atomic<int64_t> and an array of bytes. The + * byte array has an associated hash. This class provides methods to read and write the fields + * of the block but it does not interpret the fields. + * + * On initialization, all fields are set to zero. + * + * In general, methods do not report errors. This allows the methods to be used in + * CriticalNative JNI APIs. + * + * The template is parameterized by the number of nonces it supports and the number of bytes in + * the string block. */ -static const int MAX_NONCE = 64; -static const int BYTE_BLOCK_SIZE = 8192; +template<int maxNonce, size_t maxByte> class CacheNonce : public NonceStore { + + // The array of nonces + volatile nonce_t mNonce[maxNonce]; -// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes. -typedef CacheNonce<MAX_NONCE, BYTE_BLOCK_SIZE> SystemCacheNonce; + // The byte array. This is not atomic but it is guarded by the mByteHash. + volatile block_t mByteBlock[maxByte]; + + public: + // Construct and initialize the memory. + CacheNonce() : + NonceStore(maxNonce, maxByte, &mNonce[0], &mByteBlock[0]) + { + for (int i = 0; i < maxNonce; i++) { + mNonce[i] = UNSET; + } + mByteHash = UNSET; + memset((void*) mByteBlock, UNSET, sizeof(mByteBlock)); + } +}; -// The goal of this assertion is to ensure that the data structure is the same size across 32-bit -// and 64-bit systems. -static_assert(sizeof(SystemCacheNonce) == SystemCacheNonce::expectedSize, - "Unexpected SystemCacheNonce size"); +// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes. This is +// more than enough for system_server PropertyInvalidatedCache support. The configuration +// values are not defined as visible constants. Clients should use the accessors on the +// SystemCacheNonce instance if they need the sizing parameters. +typedef CacheNonce</* max nonce */ 64, /* byte block size */ 8192> SystemCacheNonce; -} // namespace PropertyInvalidatedCache -} // namespace app -} // namespace android +} // namespace android.app.PropertyInvalidatedCache diff --git a/core/jni/android_database_SQLiteRawStatement.cpp b/core/jni/android_database_SQLiteRawStatement.cpp index 85a6bdf95928..32c2ef73a5b1 100644 --- a/core/jni/android_database_SQLiteRawStatement.cpp +++ b/core/jni/android_database_SQLiteRawStatement.cpp @@ -70,12 +70,32 @@ static void throwInvalidParameter(JNIEnv *env, jlong stmtPtr, jint index) { } } +// If the last operation failed, throw an exception and return true. Otherwise return false. +static bool throwIfError(JNIEnv *env, jlong stmtPtr) { + switch (sqlite3_errcode(db(stmtPtr))) { + case SQLITE_OK: + case SQLITE_DONE: + case SQLITE_ROW: return false; + } + throw_sqlite3_exception(env, db(stmtPtr), nullptr); + return true; +} -// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out -// of bounds. It returns true if an exception was thrown. +// This throws a SQLiteBindOrColumnIndexOutOfRangeException if the column index is out of +// bounds. It throws SQLiteMisuseException if the statement's column count is zero; that +// generally occurs because the client has forgotten to call step() or the client has stepped +// past the end of the query. The function returns true if an exception was thrown. static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { - if (col < 0 || col >= sqlite3_data_count(stmt(stmtPtr))) { - int count = sqlite3_data_count(stmt(stmtPtr)); + int count = sqlite3_data_count(stmt(stmtPtr)); + if (throwIfError(env, stmtPtr)) { + return true; + } else if (count == 0) { + // A count of zero indicates a misuse: the statement has never been step()'ed. + const char* message = "row has no data"; + const char* errmsg = sqlite3_errstr(SQLITE_MISUSE); + throw_sqlite3_exception(env, SQLITE_MISUSE, errmsg, message); + return true; + } else if (col < 0 || col >= count) { std::string message = android::base::StringPrintf( "column index %d out of bounds [0,%d]", col, count - 1); char const * errmsg = sqlite3_errstr(SQLITE_RANGE); @@ -86,17 +106,6 @@ static bool throwIfInvalidColumn(JNIEnv *env, jlong stmtPtr, jint col) { } } -// If the last operation failed, throw an exception and return true. Otherwise return false. -static bool throwIfError(JNIEnv *env, jlong stmtPtr) { - switch (sqlite3_errcode(db(stmtPtr))) { - case SQLITE_OK: - case SQLITE_DONE: - case SQLITE_ROW: return false; - } - throw_sqlite3_exception(env, db(stmtPtr), nullptr); - return true; -} - static jint bindParameterCount(JNIEnv* env, jclass, jlong stmtPtr) { return sqlite3_bind_parameter_count(stmt(stmtPtr)); } 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/Android.bp b/core/res/Android.bp index 903d08b9a2ab..be4fb8bdecfb 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -179,6 +179,7 @@ android_app { "art-aconfig-flags", "ranging_aconfig_flags", "aconfig_settingslib_flags", + "telephony_flags", ], } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d0a5318be72c..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 --> @@ -7042,6 +7049,13 @@ <permission android:name="android.permission.MANAGE_SUBSCRIPTION_PLANS" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allows for reading subscription plan fields for status and end date. + @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + --> + <permission android:name="android.permission.READ_SUBSCRIPTION_PLANS" + android:protectionLevel="signature|privileged" + android:featureFlag="com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date" /> + <!-- C2DM permission. @hide Used internally. --> @@ -8785,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/color-watch-v36/btn_material_filled_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml index 70aace4e7d76..39b5b10a774d 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_background_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/disabledAlpha" - android:color="?attr/materialColorOnSurface" /> - <item android:color="?attr/materialColorPrimary" /> + android:color="@color/materialColorOnSurface" /> + <item android:color="@color/materialColorPrimary" /> </selector>
\ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_content_color.xml b/core/res/res/color-watch-v36/btn_material_filled_content_color.xml index 4cc8fe5ecb91..a70586b08bab 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_content_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_content_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/primaryContentAlpha" - android:color="?attr/materialColorOnSurface" /> - <item android:color="?attr/materialColorOnPrimary" /> + android:color="@color/materialColorOnSurface" /> + <item android:color="@color/materialColorOnPrimary" /> </selector>
\ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml index b2a25af0d670..e2e274efb2b1 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_background_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/disabledAlpha" - android:color="?attr/materialColorOnSurface" /> - <item android:color="?attr/materialColorSurfaceContainer" /> + android:color="@color/materialColorOnSurface" /> + <item android:color="@color/materialColorSurfaceContainer" /> </selector>
\ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml b/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml index 59810356c3b4..32de68868d53 100644 --- a/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml +++ b/core/res/res/color-watch-v36/btn_material_filled_tonal_content_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/primaryContentAlpha" - android:color="?attr/materialColorOnSurface" /> - <item android:color="?attr/materialColorOnSurface" /> + android:color="@color/materialColorOnSurface" /> + <item android:color="@color/materialColorOnSurface" /> </selector>
\ No newline at end of file diff --git a/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml b/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml index 665f47faca0d..3f43ca7b91df 100644 --- a/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml +++ b/core/res/res/color-watch-v36/btn_material_outlined_background_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:alpha="?attr/disabledAlpha" - android:color="?attr/materialColorOnSurface" /> - <item android:color="?attr/materialColorOutline" /> + android:color="@color/materialColorOnSurface" /> + <item android:color="@color/materialColorOutline" /> </selector> diff --git a/core/res/res/color/input_method_switch_on_item.xml b/core/res/res/color/input_method_switch_on_item.xml index 49fe0815c757..f38e0ac3454e 100644 --- a/core/res/res/color/input_method_switch_on_item.xml +++ b/core/res/res/color/input_method_switch_on_item.xml @@ -16,6 +16,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_activated="true" android:color="?attr/materialColorOnSecondaryContainer" /> - <item android:color="?attr/materialColorOnSurface" /> + <item android:state_activated="true" android:color="@color/materialColorOnSecondaryContainer" /> + <item android:color="@color/materialColorOnSurface" /> </selector> diff --git a/core/res/res/color/notification_expand_button_state_tint.xml b/core/res/res/color/notification_expand_button_state_tint.xml index 5a8594f0e461..3409a2c7ab14 100644 --- a/core/res/res/color/notification_expand_button_state_tint.xml +++ b/core/res/res/color/notification_expand_button_state_tint.xml @@ -16,9 +16,9 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnPrimaryFixed" + <item android:state_pressed="true" android:color="@androidprv:color/materialColorOnPrimaryFixed" android:alpha="0.15"/> - <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnPrimaryFixed" + <item android:state_hovered="true" android:color="@androidprv:color/materialColorOnPrimaryFixed" android:alpha="0.11"/> <item android:color="@color/transparent" /> </selector>
\ No newline at end of file diff --git a/core/res/res/color/system_on_surface_disabled.xml b/core/res/res/color/system_on_surface_disabled.xml index aba87f543c44..039ab024a32a 100644 --- a/core/res/res/color/system_on_surface_disabled.xml +++ b/core/res/res/color/system_on_surface_disabled.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="?attr/materialColorOnSurface" + <item android:color="@color/materialColorOnSurface" android:alpha="?attr/disabledAlpha" /> </selector> diff --git a/core/res/res/color/system_outline_disabled.xml b/core/res/res/color/system_outline_disabled.xml index 0a67ce3bf186..b5a6b6bd8e25 100644 --- a/core/res/res/color/system_outline_disabled.xml +++ b/core/res/res/color/system_outline_disabled.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="?attr/materialColorOutline" + <item android:color="@color/materialColorOutline" android:alpha="?attr/disabledAlpha" /> </selector> diff --git a/core/res/res/color/system_surface_disabled.xml b/core/res/res/color/system_surface_disabled.xml index 2d7fe7d727be..157227241d44 100644 --- a/core/res/res/color/system_surface_disabled.xml +++ b/core/res/res/color/system_surface_disabled.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="?attr/materialColorSurface" + <item android:color="@color/materialColorSurface" android:alpha="?attr/disabledAlpha" /> </selector> diff --git a/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml index 5c0e5f606d81..8250ee600a8f 100644 --- a/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml +++ b/core/res/res/drawable-watch-v36/progress_ring_wear_material3.xml @@ -27,7 +27,7 @@ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" android:thickness="@dimen/progressbar_thickness" android:useLevel="false"> - <solid android:color="?attr/materialColorSurfaceContainer"/> + <solid android:color="@color/materialColorSurfaceContainer"/> </shape> </item> <item> @@ -36,7 +36,7 @@ android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" android:thickness="@dimen/progressbar_thickness" android:useLevel="true"> - <solid android:color="?attr/materialColorPrimary"/> + <solid android:color="@color/materialColorPrimary"/> </shape> </item> </layer-list> diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background.xml index 99acedf06e2d..7200954140b7 100644 --- a/core/res/res/drawable/floating_popup_background.xml +++ b/core/res/res/drawable/floating_popup_background.xml @@ -18,7 +18,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHighest"/> <corners android:radius="?android:attr/dialogCornerRadius" /> </shape> diff --git a/core/res/res/drawable/immersive_cling_bg.xml b/core/res/res/drawable/immersive_cling_bg.xml index de29c32390e1..b28a423ea06b 100644 --- a/core/res/res/drawable/immersive_cling_bg.xml +++ b/core/res/res/drawable/immersive_cling_bg.xml @@ -20,5 +20,5 @@ <corners android:bottomLeftRadius="28dp" android:bottomRightRadius="28dp"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape> diff --git a/core/res/res/drawable/input_method_switch_button.xml b/core/res/res/drawable/input_method_switch_button.xml index 396d81ed87f6..1ee9b81a855a 100644 --- a/core/res/res/drawable/input_method_switch_button.xml +++ b/core/res/res/drawable/input_method_switch_button.xml @@ -30,7 +30,7 @@ <shape android:shape="rectangle"> <corners android:radius="28dp"/> <solid android:color="@color/transparent"/> - <stroke android:color="?attr/materialColorPrimary" + <stroke android:color="@color/materialColorPrimary" android:width="1dp"/> <padding android:left="16dp" android:top="8dp" diff --git a/core/res/res/drawable/input_method_switch_item_background.xml b/core/res/res/drawable/input_method_switch_item_background.xml index eb7a24691f37..ce5b6f92e539 100644 --- a/core/res/res/drawable/input_method_switch_item_background.xml +++ b/core/res/res/drawable/input_method_switch_item_background.xml @@ -29,7 +29,7 @@ <item android:state_activated="true"> <shape android:shape="rectangle"> <corners android:radius="28dp"/> - <solid android:color="?attr/materialColorSecondaryContainer"/> + <solid android:color="@color/materialColorSecondaryContainer"/> </shape> </item> </selector> diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml index 0b3861cad252..f6e6adfb4b28 100644 --- a/core/res/res/layout/floating_popup_menu_button.xml +++ b/core/res/res/layout/floating_popup_menu_button.xml @@ -54,7 +54,7 @@ android:ellipsize="end" android:fontFamily="@*android:string/config_bodyFontFamily" android:textSize="@dimen/floating_toolbar_text_size" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:background="@null" android:focusable="false" android:focusableInTouchMode="false" diff --git a/core/res/res/layout/floating_popup_overflow_button.xml b/core/res/res/layout/floating_popup_overflow_button.xml index a51836b35057..5fd774f9c3af 100644 --- a/core/res/res/layout/floating_popup_overflow_button.xml +++ b/core/res/res/layout/floating_popup_overflow_button.xml @@ -26,4 +26,4 @@ android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding" android:scaleType="centerInside" android:background="?attr/actionBarItemBackground" - android:tint="?androidprv:attr/materialColorOnSurface" /> + android:tint="@androidprv:color/materialColorOnSurface" /> diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml index 2cde9e648276..4e869b76b510 100644 --- a/core/res/res/layout/immersive_mode_cling.xml +++ b/core/res/res/layout/immersive_mode_cling.xml @@ -42,7 +42,7 @@ android:layout_marginTop="20dp" android:gravity="center_horizontal" android:text="@string/immersive_cling_title" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="24sp" android:fontFamily="google-sans" /> @@ -54,7 +54,7 @@ android:paddingTop="14dp" android:gravity="center_horizontal" android:text="@string/immersive_cling_description" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textSize="14sp" android:fontFamily="google-sans" /> @@ -72,7 +72,7 @@ android:minWidth="48dp" android:minHeight="48dp" android:text="@string/immersive_cling_positive" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" android:textAllCaps="false" android:textSize="14sp" android:textFontWeight="500" diff --git a/core/res/res/layout/input_method_switch_item_divider.xml b/core/res/res/layout/input_method_switch_item_divider.xml index 4f8c963ff8cf..b56cfb7bf6bd 100644 --- a/core/res/res/layout/input_method_switch_item_divider.xml +++ b/core/res/res/layout/input_method_switch_item_divider.xml @@ -26,7 +26,7 @@ <View android:layout_width="match_parent" android:layout_height="1dp" - android:background="?attr/materialColorOutlineVariant" + android:background="@color/materialColorOutlineVariant" android:layout_marginStart="20dp" android:layout_marginEnd="24dp" android:importantForAccessibility="no"/> diff --git a/core/res/res/layout/input_method_switch_item_header.xml b/core/res/res/layout/input_method_switch_item_header.xml index f0080a630025..05c73d04d715 100644 --- a/core/res/res/layout/input_method_switch_item_header.xml +++ b/core/res/res/layout/input_method_switch_item_header.xml @@ -33,6 +33,6 @@ android:fontFamily="google-sans-text" android:textAppearance="?attr/textAppearance" android:accessibilityHeading="true" - android:textColor="?attr/materialColorPrimary"/> + android:textColor="@color/materialColorPrimary"/> </LinearLayout> diff --git a/core/res/res/layout/input_method_switch_item_new.xml b/core/res/res/layout/input_method_switch_item_new.xml index 7b241aff3fb1..368860848f5d 100644 --- a/core/res/res/layout/input_method_switch_item_new.xml +++ b/core/res/res/layout/input_method_switch_item_new.xml @@ -56,7 +56,7 @@ android:marqueeRepeatLimit="1" android:singleLine="true" android:fontFamily="google-sans-text" - android:textColor="?attr/materialColorOnSurfaceVariant" + android:textColor="@color/materialColorOnSurfaceVariant" android:textAppearance="?attr/textAppearanceListItemSecondary" android:textAllCaps="true" android:visibility="gone"/> diff --git a/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml b/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml index b25adaabf8e8..68eafee03848 100644 --- a/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml +++ b/core/res/res/layout/notification_2025_conversation_face_pile_layout.xml @@ -18,14 +18,14 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/conversation_face_pile" - android:layout_width="@dimen/conversation_avatar_size" - android:layout_height="@dimen/conversation_avatar_size" + android:layout_width="@dimen/notification_2025_icon_circle_size" + android:layout_height="@dimen/notification_2025_icon_circle_size" android:forceHasOverlappingRendering="false" > <ImageView android:id="@+id/conversation_face_pile_top" - android:layout_width="@dimen/messaging_avatar_size" - android:layout_height="@dimen/messaging_avatar_size" + android:layout_width="@dimen/notification_2025_face_pile_avatar_size" + android:layout_height="@dimen/notification_2025_face_pile_avatar_size" android:scaleType="centerCrop" android:layout_gravity="end|top" android:background="@drawable/notification_icon_circle" @@ -43,8 +43,8 @@ /> <ImageView android:id="@+id/conversation_face_pile_bottom" - android:layout_width="@dimen/messaging_avatar_size" - android:layout_height="@dimen/messaging_avatar_size" + android:layout_width="@dimen/notification_2025_face_pile_avatar_size" + android:layout_height="@dimen/notification_2025_face_pile_avatar_size" android:scaleType="centerCrop" android:layout_gravity="center" android:background="@drawable/notification_icon_circle" diff --git a/core/res/res/layout/notification_2025_conversation_header.xml b/core/res/res/layout/notification_2025_conversation_header.xml new file mode 100644 index 000000000000..db79e79c96df --- /dev/null +++ b/core/res/res/layout/notification_2025_conversation_header.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<com.android.internal.widget.ConversationHeaderLinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/conversation_header" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingTop="@dimen/notification_2025_margin" + > + + <TextView + android:id="@+id/conversation_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" + android:textSize="16sp" + android:singleLine="true" + android:layout_weight="1" + /> + + <TextView + android:id="@+id/app_name_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:singleLine="true" + android:visibility="gone" + /> + + <!-- App Name --> + <com.android.internal.widget.ObservableTextView + android:id="@+id/app_name_text" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:singleLine="true" + android:visibility="gone" + /> + + <TextView + android:id="@+id/time_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:singleLine="true" + android:visibility="gone" + /> + + <DateTimeView + android:id="@+id/time" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:showRelative="true" + android:singleLine="true" + android:visibility="gone" + /> + + <ViewStub + android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout="@layout/notification_template_part_chronometer" + android:visibility="gone" + /> + + <TextView + android:id="@+id/verification_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:singleLine="true" + android:visibility="gone" + /> + + <ImageView + android:id="@+id/verification_icon" + android:layout_width="@dimen/notification_verification_icon_size" + android:layout_height="@dimen/notification_verification_icon_size" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:baseline="10dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_notifications_alerted" + android:visibility="gone" + /> + + <TextView + android:id="@+id/verification_text" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout_weight="100" + android:showRelative="true" + android:singleLine="true" + android:visibility="gone" + /> + + <ImageButton + android:id="@+id/feedback" + android:layout_width="@dimen/notification_feedback_size" + android:layout_height="@dimen/notification_feedback_size" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:background="?android:selectableItemBackgroundBorderless" + android:contentDescription="@string/notification_feedback_indicator" + android:baseline="13dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_feedback_indicator" + android:visibility="gone" + /> + + <ImageView + android:id="@+id/phishing_alert" + android:layout_width="@dimen/notification_phishing_alert_size" + android:layout_height="@dimen/notification_phishing_alert_size" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:baseline="10dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_dialog_alert_material" + android:visibility="gone" + android:contentDescription="@string/notification_phishing_alert_content_description" + /> + + <ImageView + android:id="@+id/profile_badge" + android:layout_width="@dimen/notification_badge_size" + android:layout_height="@dimen/notification_badge_size" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:baseline="10dp" + android:scaleType="fitCenter" + android:visibility="gone" + android:contentDescription="@string/notification_work_profile_content_description" + /> + + <ImageView + android:id="@+id/alerted_icon" + android:layout_width="@dimen/notification_alerted_size" + android:layout_height="@dimen/notification_alerted_size" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:baseline="10dp" + android:contentDescription="@string/notification_alerted_content_description" + android:scaleType="fitCenter" + android:src="@drawable/ic_notifications_alerted" + android:visibility="gone" + /> +</com.android.internal.widget.ConversationHeaderLinearLayout> diff --git a/core/res/res/layout/notification_2025_conversation_icon_container.xml b/core/res/res/layout/notification_2025_conversation_icon_container.xml index 90befd911bdf..7ec2450ceb71 100644 --- a/core/res/res/layout/notification_2025_conversation_icon_container.xml +++ b/core/res/res/layout/notification_2025_conversation_icon_container.xml @@ -18,32 +18,27 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/conversation_icon_container" - android:layout_width="@dimen/conversation_content_start" + android:layout_width="@dimen/notification_2025_content_margin_start" android:layout_height="wrap_content" android:gravity="start|top" android:clipChildren="false" android:clipToPadding="false" - android:paddingTop="20dp" - android:paddingBottom="16dp" android:importantForAccessibility="no" > <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_margin="@dimen/notification_2025_margin" android:clipChildren="false" android:clipToPadding="false" android:layout_gravity="top|center_horizontal" > - <!-- Big icon: 48x48, 12dp padding top, 16dp padding sides --> <com.android.internal.widget.CachingIconView android:id="@+id/conversation_icon" - android:layout_width="@dimen/conversation_avatar_size" - android:layout_height="@dimen/conversation_avatar_size" - android:layout_marginLeft="@dimen/conversation_badge_protrusion" - android:layout_marginRight="@dimen/conversation_badge_protrusion" - android:layout_marginBottom="@dimen/conversation_badge_protrusion" + android:layout_width="@dimen/notification_2025_icon_circle_size" + android:layout_height="@dimen/notification_2025_icon_circle_size" android:background="@drawable/notification_icon_circle" android:clipToOutline="true" android:scaleType="centerCrop" @@ -52,19 +47,25 @@ <ViewStub android:layout="@layout/notification_2025_conversation_face_pile_layout" - android:layout_width="@dimen/conversation_avatar_size" - android:layout_height="@dimen/conversation_avatar_size" - android:layout_marginLeft="@dimen/conversation_badge_protrusion" - android:layout_marginRight="@dimen/conversation_badge_protrusion" - android:layout_marginBottom="@dimen/conversation_badge_protrusion" + android:layout_width="@dimen/notification_2025_icon_circle_size" + android:layout_height="@dimen/notification_2025_icon_circle_size" android:id="@+id/conversation_face_pile" /> + <!-- The badge icon is visually aligned to the square containing the conversation icon, + but it has a border in the color of the background that is meant to delimit it from the + conversation icon. This border, although not visible due to the color, is technically + outside these bounds. + In order to align the badge properly to the bottom end of the square, we use a top/start + margin that is equal to (size of the conversation icon - size of the badge - size of the + border on one side). + --> <FrameLayout android:id="@+id/conversation_icon_badge" - android:layout_width="@dimen/conversation_icon_size_badged" - android:layout_height="@dimen/conversation_icon_size_badged" - android:layout_gravity="end|bottom" + android:layout_width="@dimen/notification_2025_conversation_icon_badge_size" + android:layout_height="@dimen/notification_2025_conversation_icon_badge_size" + android:layout_marginTop="@dimen/notification_2025_conversation_icon_badge_position" + android:layout_marginStart="@dimen/notification_2025_conversation_icon_badge_position" android:clipChildren="false" android:clipToPadding="false" > @@ -83,7 +84,7 @@ android:id="@+id/icon" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_margin="4dp" + android:layout_margin="@dimen/notification_2025_conversation_icon_badge_padding" android:layout_gravity="center" android:forceHasOverlappingRendering="false" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml index 09c02c9994f4..76c810bdb2c1 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_base.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml @@ -28,8 +28,8 @@ android:id="@+id/left_icon" android:layout_width="@dimen/notification_2025_left_icon_size" android:layout_height="@dimen/notification_2025_left_icon_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_left_icon_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" @@ -41,8 +41,8 @@ android:id="@+id/icon" android:layout_width="@dimen/notification_2025_icon_circle_size" android:layout_height="@dimen/notification_2025_icon_circle_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_icon_circle_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_icon_circle" android:padding="@dimen/notification_2025_icon_circle_padding" android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size" diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml index 614444d6b2f0..c4bca1142ece 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_call.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml @@ -41,13 +41,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginStart="@dimen/conversation_content_start" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:orientation="vertical" android:paddingBottom="@dimen/notification_2025_margin" > <include - layout="@layout/notification_template_conversation_header" + layout="@layout/notification_2025_conversation_header" android:layout_width="wrap_content" android:layout_height="wrap_content" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml index f539105368e7..2e0a7afc3cd1 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_media.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml @@ -32,8 +32,8 @@ android:id="@+id/left_icon" android:layout_width="@dimen/notification_2025_left_icon_size" android:layout_height="@dimen/notification_2025_left_icon_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_left_icon_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" @@ -45,8 +45,8 @@ android:id="@+id/icon" android:layout_width="@dimen/notification_2025_icon_circle_size" android:layout_height="@dimen/notification_2025_icon_circle_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_icon_circle_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_icon_circle" android:padding="@dimen/notification_2025_icon_circle_padding" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml index ddf3ebceaa46..f644adefda9d 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml @@ -46,8 +46,8 @@ android:id="@+id/left_icon" android:layout_width="@dimen/notification_2025_left_icon_size" android:layout_height="@dimen/notification_2025_left_icon_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_left_icon_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" @@ -59,8 +59,8 @@ android:id="@+id/icon" android:layout_width="@dimen/notification_2025_icon_circle_size" android:layout_height="@dimen/notification_2025_icon_circle_size" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/notification_icon_circle_start" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_icon_circle" android:padding="@dimen/notification_2025_icon_circle_padding" /> diff --git a/core/res/res/layout/notification_2025_template_conversation.xml b/core/res/res/layout/notification_2025_template_conversation.xml index 0c4c7fba90b1..f31f65e90950 100644 --- a/core/res/res/layout/notification_2025_template_conversation.xml +++ b/core/res/res/layout/notification_2025_template_conversation.xml @@ -60,11 +60,11 @@ <!-- Use layout_marginStart instead of paddingStart to work around strange measurement behavior on lower display densities. --> <include - layout="@layout/notification_template_conversation_header" + layout="@layout/notification_2025_conversation_header" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="2dp" - android:layout_marginStart="@dimen/conversation_content_start" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" /> <!-- Messages --> @@ -86,7 +86,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/notification_content_margin" - android:layout_marginStart="@dimen/conversation_content_start" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" /> <include layout="@layout/notification_material_action_list" /> </com.android.internal.widget.RemeasuringLinearLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml index 3ff71b78835d..2af0ec2972df 100644 --- a/core/res/res/layout/notification_2025_template_expanded_call.xml +++ b/core/res/res/layout/notification_2025_template_expanded_call.xml @@ -49,13 +49,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginStart="@dimen/conversation_content_start" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:orientation="vertical" android:minHeight="68dp" > <include - layout="@layout/notification_template_conversation_header" + layout="@layout/notification_2025_conversation_header" android:layout_width="wrap_content" android:layout_height="wrap_content" /> @@ -97,7 +97,7 @@ layout="@layout/notification_template_smart_reply_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/notification_content_margin_start" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" android:layout_marginEnd="@dimen/notification_content_margin_end" android:layout_marginTop="@dimen/notification_content_margin" /> diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml index b7fe454e09d4..63872aff8dd0 100644 --- a/core/res/res/layout/notification_2025_template_header.xml +++ b/core/res/res/layout/notification_2025_template_header.xml @@ -33,8 +33,7 @@ android:layout_width="@dimen/notification_2025_left_icon_size" android:layout_height="@dimen/notification_2025_left_icon_size" android:layout_alignParentStart="true" - android:layout_centerVertical="true" - android:layout_marginStart="@dimen/notification_left_icon_start" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_large_icon_outline" android:clipToOutline="true" android:importantForAccessibility="no" @@ -47,8 +46,7 @@ android:layout_width="@dimen/notification_2025_icon_circle_size" android:layout_height="@dimen/notification_2025_icon_circle_size" android:layout_alignParentStart="true" - android:layout_centerVertical="true" - android:layout_marginStart="@dimen/notification_icon_circle_start" + android:layout_margin="@dimen/notification_2025_margin" android:background="@drawable/notification_icon_circle" android:padding="@dimen/notification_2025_icon_circle_padding" android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size" diff --git a/core/res/res/layout/notification_2025_text.xml b/core/res/res/layout/notification_2025_text.xml index 48b1083a5e53..474f6d2099c6 100644 --- a/core/res/res/layout/notification_2025_text.xml +++ b/core/res/res/layout/notification_2025_text.xml @@ -21,6 +21,7 @@ android:layout_height="@dimen/notification_text_height" android:layout_gravity="top" android:layout_marginTop="@dimen/notification_text_margin_top" + android:ellipsize="end" android:fadingEdge="horizontal" android:gravity="top" android:maxLines="1" 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/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml index 7ac17595a278..60aec5342b4f 100644 --- a/core/res/res/values-watch/themes_device_defaults.xml +++ b/core/res/res/values-watch/themes_device_defaults.xml @@ -226,52 +226,6 @@ a similar way. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorInversePrimary">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorInverseSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorError">@color/system_error_dark</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> @@ -376,8 +330,8 @@ a similar way. <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_device_default</item> </style> - <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller - screens (small, normal) or as a dialog on larger screens (large, xlarge). --> + <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller + screens (small, normal) or as a dialog on larger screens (large, xlarge). --> <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge"> <!-- Color palette Dark --> <item name="colorPrimary">@color/primary_device_default_dark</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 238aca556003..792974defe07 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1217,178 +1217,6 @@ a value of 'true' will not override any 'false' value in its parent chain nor will it prevent any 'false' in any of its children. --> <attr name="forceDarkAllowed" format="boolean" /> - - <!-- Dynamic Tokens --> - - <!-- @hide --> - <attr name="materialColorBackground" format="color"/> - <!-- @hide --> - <attr name="materialColorControlActivated" format="color"/> - <!-- @hide --> - <attr name="materialColorControlHighlight" format="color"/> - <!-- @hide --> - <attr name="materialColorControlNormal" format="color"/> - <!-- @hide --> - <attr name="materialColorError" format="color"/> - <!-- @hide --> - <attr name="materialColorErrorContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorInverseOnSurface" format="color"/> - <!-- @hide --> - <attr name="materialColorInversePrimary" format="color"/> - <!-- @hide --> - <attr name="materialColorInverseSurface" format="color"/> - <!-- @hide --> - <attr name="materialColorOnBackground" format="color"/> - <!-- @hide --> - <attr name="materialColorOnError" format="color"/> - <!-- @hide --> - <attr name="materialColorOnErrorContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorOnPrimary" format="color"/> - <!-- @hide --> - <attr name="materialColorOnPrimaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSecondary" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSecondaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSurface" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSurfaceVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorOnTertiary" format="color"/> - <!-- @hide --> - <attr name="materialColorOnTertiaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorOutline" format="color"/> - <!-- @hide --> - <attr name="materialColorOutlineVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorPaletteKeyColorNeutral" format="color"/> - <!-- @hide --> - <attr name="materialColorPaletteKeyColorNeutralVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorPaletteKeyColorPrimary" format="color"/> - <!-- @hide --> - <attr name="materialColorPaletteKeyColorSecondary" format="color"/> - <!-- @hide --> - <attr name="materialColorPaletteKeyColorTertiary" format="color"/> - <!-- @hide --> - <attr name="materialColorPrimary" format="color"/> - <!-- @hide --> - <attr name="materialColorPrimaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorScrim" format="color"/> - <!-- @hide --> - <attr name="materialColorSecondary" format="color"/> - <!-- @hide --> - <attr name="materialColorSecondaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorShadow" format="color"/> - <!-- @hide --> - <attr name="materialColorSurface" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceBright" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceContainerHigh" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceContainerHighest" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceContainerLow" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceContainerLowest" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceDim" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceTint" format="color"/> - <!-- @hide --> - <attr name="materialColorSurfaceVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorTertiary" format="color"/> - <!-- @hide --> - <attr name="materialColorTertiaryContainer" format="color"/> - <!-- @hide --> - <attr name="materialColorTextHintInverse" format="color"/> - <!-- @hide --> - <attr name="materialColorTextPrimaryInverse" format="color"/> - <!-- @hide --> - <attr name="materialColorTextPrimaryInverseDisableOnly" format="color"/> - <!-- @hide --> - <attr name="materialColorTextSecondaryAndTertiaryInverse" format="color"/> - <!-- @hide --> - <attr name="materialColorTextSecondaryAndTertiaryInverseDisabled" format="color"/> - <!-- @hide --> - <attr name="materialColorOnPrimaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorOnPrimaryFixedVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSecondaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorOnSecondaryFixedVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorOnTertiaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorOnTertiaryFixedVariant" format="color"/> - <!-- @hide --> - <attr name="materialColorPrimaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorPrimaryFixedDim" format="color"/> - <!-- @hide --> - <attr name="materialColorSecondaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorSecondaryFixedDim" format="color"/> - <!-- @hide --> - <attr name="materialColorTertiaryFixed" format="color"/> - <!-- @hide --> - <attr name="materialColorTertiaryFixedDim" format="color"/> - <!-- @hide --> - <attr name="customColorBrandA" format="color"/> - <!-- @hide --> - <attr name="customColorBrandB" format="color"/> - <!-- @hide --> - <attr name="customColorBrandC" format="color"/> - <!-- @hide --> - <attr name="customColorBrandD" format="color"/> - <!-- @hide --> - <attr name="customColorClockHour" format="color"/> - <!-- @hide --> - <attr name="customColorClockMinute" format="color"/> - <!-- @hide --> - <attr name="customColorClockSecond" format="color"/> - <!-- @hide --> - <attr name="customColorOnShadeActive" format="color"/> - <!-- @hide --> - <attr name="customColorOnShadeActiveVariant" format="color"/> - <!-- @hide --> - <attr name="customColorOnShadeInactive" format="color"/> - <!-- @hide --> - <attr name="customColorOnShadeInactiveVariant" format="color"/> - <!-- @hide --> - <attr name="customColorOnThemeApp" format="color"/> - <!-- @hide --> - <attr name="customColorOverviewBackground" format="color"/> - <!-- @hide --> - <attr name="customColorShadeActive" format="color"/> - <!-- @hide --> - <attr name="customColorShadeDisabled" format="color"/> - <!-- @hide --> - <attr name="customColorShadeInactive" format="color"/> - <!-- @hide --> - <attr name="customColorThemeApp" format="color"/> - <!-- @hide --> - <attr name="customColorThemeAppRing" format="color"/> - <!-- @hide --> - <attr name="customColorThemeNotif" format="color"/> - <!-- @hide --> - <attr name="customColorUnderSurface" format="color"/> - <!-- @hide --> - <attr name="customColorWeatherTemp" format="color"/> - <!-- @hide --> - <attr name="customColorWidgetBackground" format="color"/> - </declare-styleable> <!-- **************************************************************** --> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 00c59c6c0edc..a06d184fd147 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2572,7 +2572,9 @@ against a development branch, in which case it will only work against the development builds. --> <attr name="minSdkVersion" format="integer|string" /> - <!-- @FlaggedApi(android.sdk.Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) --> + <!-- This is the minimum SDK major and minor version (e.g. "36.1") that + the application requires. Verified independently of minSdkVersion. + @FlaggedApi(android.sdk.Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) --> <attr name="minSdkVersionFull" format="string" /> <!-- This is the SDK version number that the application is targeting. It is able to run on older versions (down to minSdkVersion), but diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 53b47622e8ae..89184bcc3721 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -7212,10 +7212,6 @@ screen. --> <bool name="config_dragToMaximizeInDesktopMode">false</bool> - <!-- Whether showing the app handle is supported on this device. - If config_isDesktopModeSupported, then this has no effect --> - <bool name="config_enableAppHandle">false</bool> - <!-- Frame rate compatibility value for Wallpaper FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption --> <integer name="config_wallpaperFrameRateCompatibility">102</integer> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index bb76b9fae8d7..196da29127df 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -496,4 +496,8 @@ not connected state. --> <bool name="config_satellite_allow_check_message_in_not_connected">false</bool> <java-symbol type="bool" name="config_satellite_allow_check_message_in_not_connected" /> + + <!-- Whether to allow TN scanning during satellite session. --> + <bool name="config_satellite_allow_tn_scanning_during_satellite_session">true</bool> + <java-symbol type="bool" name="config_satellite_allow_tn_scanning_during_satellite_session" /> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index f53acbfac71d..51bd4cc6cc8a 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -912,6 +912,8 @@ <dimen name="conversation_icon_size_badged">20dp</dimen> <!-- size of the conversation avatar in an expanded group --> <dimen name="conversation_avatar_size_group_expanded">@dimen/messaging_avatar_size</dimen> + <!-- size of the face pile icons (2025 redesign version) --> + <dimen name="notification_2025_face_pile_avatar_size">24dp</dimen> <!-- size of the face pile icons --> <dimen name="conversation_face_pile_avatar_size">32dp</dimen> <!-- size of the face pile icons when the group is expanded --> @@ -939,6 +941,18 @@ <!-- The size of the importance ring --> <dimen name="importance_ring_size">20dp</dimen> + <!-- The spacing around the app icon badge shown next to the conversation icon --> + <dimen name="notification_2025_conversation_icon_badge_padding">2dp</dimen> + + <!-- Top and start margin for the app icon badge shown next to the conversation icon, to align + it to the bottom end corner. + 40dp (conversation icon size) - 16dp (actual size of badge) - 2dp (badge padding) --> + <dimen name="notification_2025_conversation_icon_badge_position">22dp</dimen> + + <!-- The size of the app icon badge shown next to the conversation icon, including its padding. + The actual size of the icon is 16dp, plus 2dp for each side for the padding. --> + <dimen name="notification_2025_conversation_icon_badge_size">20dp</dimen> + <!-- The top padding of the conversation icon container in the regular state--> <dimen name="conversation_icon_container_top_padding">20dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 28de553f6063..6c01994b3c93 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -5445,133 +5445,51 @@ <java-symbol name="customColorWeatherTemp" type="color"/> <java-symbol name="customColorWidgetBackground" type="color"/> - <java-symbol type="attr" name="materialColorBackground"/> - <java-symbol type="attr" name="materialColorControlActivated"/> - <java-symbol type="attr" name="materialColorControlHighlight"/> - <java-symbol type="attr" name="materialColorControlNormal"/> - <java-symbol type="attr" name="materialColorError"/> - <java-symbol type="attr" name="materialColorErrorContainer"/> - <java-symbol type="attr" name="materialColorInverseOnSurface"/> - <java-symbol type="attr" name="materialColorInversePrimary"/> - <java-symbol type="attr" name="materialColorInverseSurface"/> - <java-symbol type="attr" name="materialColorOnBackground"/> - <java-symbol type="attr" name="materialColorOnError"/> - <java-symbol type="attr" name="materialColorOnErrorContainer"/> - <java-symbol type="attr" name="materialColorOnPrimary"/> - <java-symbol type="attr" name="materialColorOnPrimaryContainer"/> - <java-symbol type="attr" name="materialColorOnSecondary"/> - <java-symbol type="attr" name="materialColorOnSecondaryContainer"/> - <java-symbol type="attr" name="materialColorOnSurface"/> - <java-symbol type="attr" name="materialColorOnSurfaceVariant"/> - <java-symbol type="attr" name="materialColorOnTertiary"/> - <java-symbol type="attr" name="materialColorOnTertiaryContainer"/> - <java-symbol type="attr" name="materialColorOutline"/> - <java-symbol type="attr" name="materialColorOutlineVariant"/> - <java-symbol type="attr" name="materialColorPaletteKeyColorNeutral"/> - <java-symbol type="attr" name="materialColorPaletteKeyColorNeutralVariant"/> - <java-symbol type="attr" name="materialColorPaletteKeyColorPrimary"/> - <java-symbol type="attr" name="materialColorPaletteKeyColorSecondary"/> - <java-symbol type="attr" name="materialColorPaletteKeyColorTertiary"/> - <java-symbol type="attr" name="materialColorPrimary"/> - <java-symbol type="attr" name="materialColorPrimaryContainer"/> - <java-symbol type="attr" name="materialColorScrim"/> - <java-symbol type="attr" name="materialColorSecondary"/> - <java-symbol type="attr" name="materialColorSecondaryContainer"/> - <java-symbol type="attr" name="materialColorShadow"/> - <java-symbol type="attr" name="materialColorSurface"/> - <java-symbol type="attr" name="materialColorSurfaceBright"/> - <java-symbol type="attr" name="materialColorSurfaceContainer"/> - <java-symbol type="attr" name="materialColorSurfaceContainerHigh"/> - <java-symbol type="attr" name="materialColorSurfaceContainerHighest"/> - <java-symbol type="attr" name="materialColorSurfaceContainerLow"/> - <java-symbol type="attr" name="materialColorSurfaceContainerLowest"/> - <java-symbol type="attr" name="materialColorSurfaceDim"/> - <java-symbol type="attr" name="materialColorSurfaceTint"/> - <java-symbol type="attr" name="materialColorSurfaceVariant"/> - <java-symbol type="attr" name="materialColorTertiary"/> - <java-symbol type="attr" name="materialColorTertiaryContainer"/> - <java-symbol type="attr" name="materialColorTextHintInverse"/> - <java-symbol type="attr" name="materialColorTextPrimaryInverse"/> - <java-symbol type="attr" name="materialColorTextPrimaryInverseDisableOnly"/> - <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverse"/> - <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverseDisabled"/> - <java-symbol type="attr" name="materialColorOnPrimaryFixed"/> - <java-symbol type="attr" name="materialColorOnPrimaryFixedVariant"/> - <java-symbol type="attr" name="materialColorOnSecondaryFixed"/> - <java-symbol type="attr" name="materialColorOnSecondaryFixedVariant"/> - <java-symbol type="attr" name="materialColorOnTertiaryFixed"/> - <java-symbol type="attr" name="materialColorOnTertiaryFixedVariant"/> - <java-symbol type="attr" name="materialColorPrimaryFixed"/> - <java-symbol type="attr" name="materialColorPrimaryFixedDim"/> - <java-symbol type="attr" name="materialColorSecondaryFixed"/> - <java-symbol type="attr" name="materialColorSecondaryFixedDim"/> - <java-symbol type="attr" name="materialColorTertiaryFixed"/> - <java-symbol type="attr" name="materialColorTertiaryFixedDim"/> - <java-symbol type="attr" name="customColorBrandA"/> - <java-symbol type="attr" name="customColorBrandB"/> - <java-symbol type="attr" name="customColorBrandC"/> - <java-symbol type="attr" name="customColorBrandD"/> - <java-symbol type="attr" name="customColorClockHour"/> - <java-symbol type="attr" name="customColorClockMinute"/> - <java-symbol type="attr" name="customColorClockSecond"/> - <java-symbol type="attr" name="customColorOnShadeActive"/> - <java-symbol type="attr" name="customColorOnShadeActiveVariant"/> - <java-symbol type="attr" name="customColorOnShadeInactive"/> - <java-symbol type="attr" name="customColorOnShadeInactiveVariant"/> - <java-symbol type="attr" name="customColorOnThemeApp"/> - <java-symbol type="attr" name="customColorOverviewBackground"/> - <java-symbol type="attr" name="customColorShadeActive"/> - <java-symbol type="attr" name="customColorShadeDisabled"/> - <java-symbol type="attr" name="customColorShadeInactive"/> - <java-symbol type="attr" name="customColorThemeApp"/> - <java-symbol type="attr" name="customColorThemeAppRing"/> - <java-symbol type="attr" name="customColorThemeNotif"/> - <java-symbol type="attr" name="customColorUnderSurface"/> - <java-symbol type="attr" name="customColorWeatherTemp"/> - <java-symbol type="attr" name="customColorWidgetBackground"/> - - <java-symbol name="system_widget_background_light" type="color"/> - <java-symbol name="system_clock_hour_light" type="color"/> - <java-symbol name="system_clock_minute_light" type="color"/> - <java-symbol name="system_clock_second_light" type="color"/> - <java-symbol name="system_theme_app_light" type="color"/> - <java-symbol name="system_on_theme_app_light" type="color"/> - <java-symbol name="system_theme_app_ring_light" type="color"/> - <java-symbol name="system_theme_notif_light" type="color"/> <java-symbol name="system_brand_a_light" type="color"/> <java-symbol name="system_brand_b_light" type="color"/> <java-symbol name="system_brand_c_light" type="color"/> <java-symbol name="system_brand_d_light" type="color"/> - <java-symbol name="system_under_surface_light" type="color"/> - <java-symbol name="system_shade_active_light" type="color"/> + <java-symbol name="system_clock_hour_light" type="color"/> + <java-symbol name="system_clock_minute_light" type="color"/> + <java-symbol name="system_clock_second_light" type="color"/> <java-symbol name="system_on_shade_active_light" type="color"/> <java-symbol name="system_on_shade_active_variant_light" type="color"/> - <java-symbol name="system_shade_inactive_light" type="color"/> <java-symbol name="system_on_shade_inactive_light" type="color"/> <java-symbol name="system_on_shade_inactive_variant_light" type="color"/> - <java-symbol name="system_shade_disabled_light" type="color"/> + <java-symbol name="system_on_theme_app_light" type="color"/> <java-symbol name="system_overview_background_light" type="color"/> - <java-symbol name="system_widget_background_dark" type="color"/> - <java-symbol name="system_clock_hour_dark" type="color"/> - <java-symbol name="system_clock_minute_dark" type="color"/> - <java-symbol name="system_clock_second_dark" type="color"/> - <java-symbol name="system_theme_app_dark" type="color"/> - <java-symbol name="system_on_theme_app_dark" type="color"/> - <java-symbol name="system_theme_app_ring_dark" type="color"/> - <java-symbol name="system_theme_notif_dark" type="color"/> + <java-symbol name="system_shade_active_light" type="color"/> + <java-symbol name="system_shade_disabled_light" type="color"/> + <java-symbol name="system_shade_inactive_light" type="color"/> + <java-symbol name="system_theme_app_light" type="color"/> + <java-symbol name="system_theme_app_ring_light" type="color"/> + <java-symbol name="system_theme_notif_light" type="color"/> + <java-symbol name="system_under_surface_light" type="color"/> + <java-symbol name="system_weather_temp_light" type="color"/> + <java-symbol name="system_widget_background_light" type="color"/> + <java-symbol name="system_brand_a_dark" type="color"/> <java-symbol name="system_brand_b_dark" type="color"/> <java-symbol name="system_brand_c_dark" type="color"/> <java-symbol name="system_brand_d_dark" type="color"/> - <java-symbol name="system_under_surface_dark" type="color"/> - <java-symbol name="system_shade_active_dark" type="color"/> + <java-symbol name="system_clock_hour_dark" type="color"/> + <java-symbol name="system_clock_minute_dark" type="color"/> + <java-symbol name="system_clock_second_dark" type="color"/> <java-symbol name="system_on_shade_active_dark" type="color"/> <java-symbol name="system_on_shade_active_variant_dark" type="color"/> - <java-symbol name="system_shade_inactive_dark" type="color"/> <java-symbol name="system_on_shade_inactive_dark" type="color"/> <java-symbol name="system_on_shade_inactive_variant_dark" type="color"/> - <java-symbol name="system_shade_disabled_dark" type="color"/> + <java-symbol name="system_on_theme_app_dark" type="color"/> <java-symbol name="system_overview_background_dark" type="color"/> + <java-symbol name="system_shade_active_dark" type="color"/> + <java-symbol name="system_shade_disabled_dark" type="color"/> + <java-symbol name="system_shade_inactive_dark" type="color"/> + <java-symbol name="system_theme_app_dark" type="color"/> + <java-symbol name="system_theme_app_ring_dark" type="color"/> + <java-symbol name="system_theme_notif_dark" type="color"/> + <java-symbol name="system_under_surface_dark" type="color"/> + <java-symbol name="system_weather_temp_dark" type="color"/> + <java-symbol name="system_widget_background_dark" type="color"/> <java-symbol type="attr" name="actionModeUndoDrawable" /> <java-symbol type="attr" name="actionModeRedoDrawable" /> @@ -5763,9 +5681,6 @@ screen. --> <java-symbol type="bool" name="config_dragToMaximizeInDesktopMode" /> - <!-- Whether showing the app handle is supported on this device --> - <java-symbol type="bool" name="config_enableAppHandle" /> - <!-- Frame rate compatibility value for Wallpaper --> <java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" /> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index d8346d87f624..6b3d4271a609 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -131,7 +131,7 @@ easier. <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item> <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="seekBarStyle">@style/Widget.DeviceDefault.SeekBar</item> <item name="ratingBarStyle">@style/Widget.DeviceDefault.RatingBar</item> <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.RatingBar.Indicator</item> @@ -238,91 +238,6 @@ easier. <item name="textColorOnAccent">@color/system_on_primary_dark</item> <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" /> @@ -368,96 +283,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme @@ -502,96 +332,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and @@ -638,96 +383,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent @@ -773,96 +433,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be @@ -916,96 +491,11 @@ easier. <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a @@ -1050,96 +540,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar --> @@ -1183,96 +588,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width @@ -1317,96 +637,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -1467,96 +702,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for a window without an action bar that will be displayed either @@ -1602,96 +752,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for a presentation window on a secondary display. --> @@ -1735,96 +800,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for panel windows. This removes all extraneous window @@ -1870,96 +850,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -2004,96 +899,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -2138,96 +948,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -2272,96 +997,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -2406,96 +1046,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> @@ -2540,96 +1095,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Theme for the dialog shown when an app crashes or ANRs. --> @@ -2679,96 +1149,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame"> @@ -2811,96 +1196,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style --> @@ -2982,7 +1282,7 @@ easier. <item name="progressBarStyleSmallInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item> <item name="progressBarStyleLargeInverse">@style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="seekBarStyle">@style/Widget.DeviceDefault.Light.SeekBar</item> <item name="ratingBarStyle">@style/Widget.DeviceDefault.Light.RatingBar</item> <item name="ratingBarStyleIndicator">@style/Widget.DeviceDefault.Light.RatingBar.Indicator</item> @@ -3086,91 +1386,6 @@ easier. <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> <item name="colorPopupBackground">?attr/colorBackgroundFloating</item> <item name="panelColorBackground">?attr/colorBackgroundFloating</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an @@ -3215,96 +1430,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar --> @@ -3348,96 +1478,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar. @@ -3482,96 +1527,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar @@ -3618,96 +1578,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent @@ -3753,96 +1628,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be @@ -3894,96 +1684,11 @@ easier. <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a @@ -4031,96 +1736,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar --> @@ -4167,96 +1787,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum @@ -4304,96 +1839,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -4427,91 +1877,6 @@ easier. <item name="textColorOnAccent">@color/system_on_primary_dark</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. --> @@ -4545,91 +1910,6 @@ easier. <item name="textColorOnAccent">@color/system_on_primary_dark</item> <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller @@ -4677,96 +1957,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a window without an action bar that will be displayed either @@ -4815,96 +2010,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a presentation window on a secondary display. --> @@ -4951,96 +2061,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for panel windows. This removes all extraneous window @@ -5086,96 +2111,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert"> @@ -5220,96 +2160,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" /> @@ -5354,96 +2209,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice"> @@ -5486,96 +2256,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> @@ -5631,90 +2316,6 @@ easier. <item name="colorListDivider">@color/list_divider_color_light</item> <item name="opacityListDivider">@color/list_divider_opacity_device_default_light</item> - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light"> @@ -5745,96 +2346,12 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog"> @@ -5857,96 +2374,12 @@ easier. <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar --> @@ -5991,96 +2424,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog"> @@ -6114,91 +2462,6 @@ easier. <!-- Dialog attributes --> <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase"> @@ -6216,7 +2479,7 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> @@ -6267,96 +2530,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> @@ -6403,96 +2581,11 @@ easier. <item name="buttonBarButtonStyle">@style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog</item> <!-- Progress bar attributes --> - <item name="colorProgressBackgroundNormal">?attr/materialColorOutline</item> + <item name="colorProgressBackgroundNormal">@color/materialColorOutline</item> <item name="progressBarCornerRadius">@dimen/config_progressBarCornerRadius</item> <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> @@ -6570,91 +2663,6 @@ easier. <item name="colorAccentPrimary">@color/accent_primary_device_default</item> <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="ThemeOverlay.DeviceDefault.Accent.Light"> @@ -6662,91 +2670,6 @@ easier. <item name="colorAccentPrimary">@color/accent_primary_device_default</item> <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. --> @@ -6758,91 +2681,6 @@ easier. <item name="colorAccentPrimary">@color/accent_primary_device_default</item> <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen"> @@ -6850,91 +2688,6 @@ easier. <item name="colorBackgroundFloating">@color/background_device_default_light</item> <item name="layout_gravity">center</item> <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item> - - <item name="materialColorBackground">@color/system_background_light</item> - <item name="materialColorControlActivated">@color/system_control_activated_light</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> - <item name="materialColorControlNormal">@color/system_control_normal_light</item> - <item name="materialColorError">@color/system_error_light</item> - <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> - <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorOutline">@color/system_outline_light</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> - <item name="materialColorPrimary">@color/system_primary_light</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> - <item name="materialColorScrim">@color/system_scrim_light</item> - <item name="materialColorSecondary">@color/system_secondary_light</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> - <item name="materialColorShadow">@color/system_shadow_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiary">@color/system_tertiary_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_light</item> - <item name="customColorBrandB">@color/system_brand_b_light</item> - <item name="customColorBrandC">@color/system_brand_c_light</item> - <item name="customColorBrandD">@color/system_brand_d_light</item> - <item name="customColorClockHour">@color/system_clock_hour_light</item> - <item name="customColorClockMinute">@color/system_clock_minute_light</item> - <item name="customColorClockSecond">@color/system_clock_second_light</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> - <item name="customColorOverviewBackground">@color/system_overview_background_light</item> - <item name="customColorShadeActive">@color/system_shade_active_light</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> - <item name="customColorThemeApp">@color/system_theme_app_light</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> - <item name="customColorThemeNotif">@color/system_theme_notif_light</item> - <item name="customColorUnderSurface">@color/system_under_surface_light</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> - <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification"> @@ -6953,91 +2706,6 @@ easier. <item name="colorAccentPrimary">@color/system_accent1_100</item> <item name="textColorPrimary">@color/system_neutral1_900</item> <item name="textColorSecondary">@color/system_neutral2_700</item> - - <item name="materialColorBackground">@color/system_background_dark</item> - <item name="materialColorControlActivated">@color/system_control_activated_dark</item> - <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> - <item name="materialColorControlNormal">@color/system_control_normal_dark</item> - <item name="materialColorError">@color/system_error_dark</item> - <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> - <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> - <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> - <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorOutline">@color/system_outline_dark</item> - <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> - <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> - <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> - <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> - <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> - <item name="materialColorPrimary">@color/system_primary_dark</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> - <item name="materialColorScrim">@color/system_scrim_dark</item> - <item name="materialColorSecondary">@color/system_secondary_dark</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> - <item name="materialColorShadow">@color/system_shadow_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiary">@color/system_tertiary_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> - <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> - <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> - <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="customColorBrandA">@color/system_brand_a_dark</item> - <item name="customColorBrandB">@color/system_brand_b_dark</item> - <item name="customColorBrandC">@color/system_brand_c_dark</item> - <item name="customColorBrandD">@color/system_brand_d_dark</item> - <item name="customColorClockHour">@color/system_clock_hour_dark</item> - <item name="customColorClockMinute">@color/system_clock_minute_dark</item> - <item name="customColorClockSecond">@color/system_clock_second_dark</item> - <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> - <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> - <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> - <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> - <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> - <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> - <item name="customColorShadeActive">@color/system_shade_active_dark</item> - <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> - <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> - <item name="customColorThemeApp">@color/system_theme_app_dark</item> - <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> - <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> - <item name="customColorUnderSurface">@color/system_under_surface_dark</item> - <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> - <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight"> <item name="colorListDivider">@color/list_divider_opacity_device_default_light</item> diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml index 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/app/NotificationManagerTest.java b/core/tests/coretests/src/android/app/NotificationManagerTest.java new file mode 100644 index 000000000000..3213abe13d8a --- /dev/null +++ b/core/tests/coretests/src/android/app/NotificationManagerTest.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.app; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Instant; +import java.time.InstantSource; + +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class NotificationManagerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + private NotificationManagerWithMockService mNotificationManager; + private final FakeClock mClock = new FakeClock(); + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mNotificationManager = new NotificationManagerWithMockService(mContext, mClock); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void notify_rapidUpdate_isThrottled() throws Exception { + Notification n = exampleNotification(); + + for (int i = 0; i < 100; i++) { + mNotificationManager.notify(1, n); + mClock.advanceByMillis(5); + } + + verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag(any(), + any(), any(), anyInt(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void notify_reasonableUpdate_isNotThrottled() throws Exception { + Notification n = exampleNotification(); + + for (int i = 0; i < 100; i++) { + mNotificationManager.notify(1, n); + mClock.advanceByMillis(300); + } + + verify(mNotificationManager.mBackendService, times(100)).enqueueNotificationWithTag(any(), + any(), any(), anyInt(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void notify_rapidAdd_isNotThrottled() throws Exception { + Notification n = exampleNotification(); + + for (int i = 0; i < 100; i++) { + mNotificationManager.notify(i, n); + mClock.advanceByMillis(5); + } + + verify(mNotificationManager.mBackendService, times(100)).enqueueNotificationWithTag(any(), + any(), any(), anyInt(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) + public void notify_rapidAddAndCancel_isNotThrottled() throws Exception { + Notification n = exampleNotification(); + + for (int i = 0; i < 100; i++) { + mNotificationManager.notify(1, n); + mNotificationManager.cancel(1); + mClock.advanceByMillis(5); + } + + verify(mNotificationManager.mBackendService, times(100)).enqueueNotificationWithTag(any(), + any(), any(), anyInt(), any(), anyInt()); + } + + private Notification exampleNotification() { + return new Notification.Builder(mContext, "channel") + .setSmallIcon(android.R.drawable.star_big_on) + .build(); + } + + private static class NotificationManagerWithMockService extends NotificationManager { + + private final INotificationManager mBackendService; + + NotificationManagerWithMockService(Context context, InstantSource clock) { + super(context, clock); + mBackendService = mock(INotificationManager.class); + } + + @Override + public INotificationManager service() { + return mBackendService; + } + } + + private static class FakeClock implements InstantSource { + + private long mNowMillis = 441644400000L; + + @Override + public Instant instant() { + return Instant.ofEpochMilli(mNowMillis); + } + + private void advanceByMillis(long millis) { + mNowMillis += millis; + } + } +} diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 63e678d9ee53..9effeec23890 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -467,12 +467,25 @@ public class NotificationTest { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); assertThat(n.hasPromotableCharacteristics()).isTrue(); } @Test @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) + public void testHasPromotableCharacteristics_notOngoing() { + Notification n = new Notification.Builder(mContext, "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) + .setColor(Color.WHITE) + .setColorized(true) + .build(); + assertThat(n.hasPromotableCharacteristics()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_UI_RICH_ONGOING) public void testHasPromotableCharacteristics_wrongStyle() { Notification n = new Notification.Builder(mContext, "test") .setSmallIcon(android.R.drawable.sym_def_app_icon) @@ -480,6 +493,7 @@ public class NotificationTest { .setContentTitle("TITLE") .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); assertThat(n.hasPromotableCharacteristics()).isFalse(); } @@ -491,6 +505,7 @@ public class NotificationTest { .setSmallIcon(android.R.drawable.sym_def_app_icon) .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) + .setOngoing(true) .build(); assertThat(n.hasPromotableCharacteristics()).isFalse(); } @@ -503,6 +518,7 @@ public class NotificationTest { .setStyle(new Notification.BigTextStyle()) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); assertThat(n.hasPromotableCharacteristics()).isFalse(); } @@ -515,6 +531,7 @@ public class NotificationTest { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setGroup("someGroup") .setGroupSummary(true) .build(); diff --git a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java index 6d2dd5355ff0..ff3abae29b4a 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java +++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java @@ -33,7 +33,6 @@ import android.content.pm.parsing.result.ParseTypeImpl; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.platform.test.annotations.Presubmit; -import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; import android.util.PackageUtils; @@ -62,7 +61,6 @@ import java.util.List; import java.util.Set; @Presubmit -@RequiresFlagsEnabled(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) public class ApkLiteParseUtilsTest { @Rule diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java index 6dad3b7b2ac4..13b12fcf300a 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java @@ -1010,6 +1010,7 @@ public class SQLiteRawStatementTest { mDatabase.beginTransaction(); try { mDatabase.execSQL("CREATE TABLE t1 (i int, j int);"); + mDatabase.execSQL("INSERT INTO t1 (i, j) VALUES (2, 20)"); mDatabase.setTransactionSuccessful(); } finally { mDatabase.endTransaction(); @@ -1017,13 +1018,35 @@ public class SQLiteRawStatementTest { mDatabase.beginTransactionReadOnly(); try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { - s.step(); - s.getColumnText(5); // out-of-range column + assertTrue(s.step()); + s.getColumnText(5); // out-of-range column: the range is [0,2). fail("JNI exception not thrown"); } catch (SQLiteBindOrColumnIndexOutOfRangeException e) { // Passing case. } finally { mDatabase.endTransaction(); } + + mDatabase.beginTransactionReadOnly(); + try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { + // Do not step the statement. The column count will be zero. + s.getColumnText(5); // out-of-range column: never stepped. + fail("JNI exception not thrown"); + } catch (SQLiteMisuseException e) { + // Passing case. + } finally { + mDatabase.endTransaction(); + } + + mDatabase.beginTransactionReadOnly(); + try (SQLiteRawStatement s = mDatabase.createRawStatement("SELECT * from t1")) { + // Do not step the statement. The column count will be zero. + s.getColumnText(0); // out-of-range column: never stepped. + fail("JNI exception not thrown"); + } catch (SQLiteMisuseException e) { + // Passing case. + } finally { + mDatabase.endTransaction(); + } } } 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/os/TestLooperManagerTest.java b/core/tests/coretests/src/android/os/TestLooperManagerTest.java deleted file mode 100644 index 4d64a3a94b41..000000000000 --- a/core/tests/coretests/src/android/os/TestLooperManagerTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -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 android.platform.test.ravenwood.RavenwoodRule; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -@RunWith(AndroidJUnit4.class) -public class TestLooperManagerTest { - private static final String TAG = "TestLooperManagerTest"; - - @Rule - public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() - .setProvideMainThread(true) - .build(); - - @Test - public void testMainThread() throws Exception { - doTest(Looper.getMainLooper()); - } - - @Test - public void testCustomThread() throws Exception { - final HandlerThread thread = new HandlerThread(TAG); - thread.start(); - doTest(thread.getLooper()); - } - - private void doTest(Looper looper) throws Exception { - final TestLooperManager tlm = - InstrumentationRegistry.getInstrumentation().acquireLooperManager(looper); - - final Handler handler = new Handler(looper); - final CountDownLatch latch = new CountDownLatch(1); - - assertFalse(tlm.hasMessages(handler, null, 42)); - - handler.sendEmptyMessage(42); - handler.post(() -> { - latch.countDown(); - }); - assertTrue(tlm.hasMessages(handler, null, 42)); - assertFalse(latch.await(100, TimeUnit.MILLISECONDS)); - - final Message first = tlm.next(); - assertEquals(42, first.what); - assertNull(first.callback); - tlm.execute(first); - assertFalse(tlm.hasMessages(handler, null, 42)); - assertFalse(latch.await(100, TimeUnit.MILLISECONDS)); - tlm.recycle(first); - - final Message second = tlm.next(); - assertNotNull(second.callback); - tlm.execute(second); - assertFalse(tlm.hasMessages(handler, null, 42)); - assertTrue(latch.await(100, TimeUnit.MILLISECONDS)); - tlm.recycle(second); - - tlm.release(); - } -} diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java index 43c404e849fe..ae3ad36b532c 100644 --- a/core/tests/coretests/src/android/view/ViewGroupTest.java +++ b/core/tests/coretests/src/android/view/ViewGroupTest.java @@ -213,35 +213,6 @@ public class ViewGroupTest { assertTrue(autofillableViews.containsAll(Arrays.asList(viewA, viewC))); } - @Test - public void testMeasureCache() { - final int spec1 = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST); - final int spec2 = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST); - final Context context = getInstrumentation().getContext(); - final View child = new View(context); - final TestView parent = new TestView(context, 0); - parent.addView(child); - - child.setPadding(1, 2, 3, 4); - parent.measure(spec1, spec1); - assertEquals(4, parent.getMeasuredWidth()); - assertEquals(6, parent.getMeasuredHeight()); - - child.setPadding(5, 6, 7, 8); - parent.measure(spec2, spec2); - assertEquals(12, parent.getMeasuredWidth()); - assertEquals(14, parent.getMeasuredHeight()); - - // This ends the state of forceLayout. - parent.layout(0, 0, 50, 50); - - // The cached values should be cleared after the new setPadding is called. And the measured - // width and height should be up-to-date. - parent.measure(spec1, spec1); - assertEquals(12, parent.getMeasuredWidth()); - assertEquals(14, parent.getMeasuredHeight()); - } - private static void getUnobscuredTouchableRegion(Region outRegion, View view) { outRegion.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); final ViewParent parent = view.getParent(); @@ -269,19 +240,6 @@ public class ViewGroupTest { protected void onLayout(boolean changed, int l, int t, int r, int b) { // We don't layout this view. } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int measuredWidth = 0; - int measuredHeight = 0; - final int count = getChildCount(); - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - measuredWidth += child.getPaddingLeft() + child.getPaddingRight(); - measuredHeight += child.getPaddingTop() + child.getPaddingBottom(); - } - setMeasuredDimension(measuredWidth, measuredHeight); - } } public static class AutofillableTestView extends TestView { 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/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp index 931eac515e31..14a3cdf98436 100644 --- a/core/tests/overlaytests/device_self_targeting/Android.bp +++ b/core/tests/overlaytests/device_self_targeting/Android.bp @@ -31,6 +31,7 @@ android_test { "androidx.test.ext.junit", "mockito-target-minus-junit4", "truth", + "flag-junit", ], optimize: { diff --git a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java index 28d6545c8a5b..bcf1446b3467 100644 --- a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java +++ b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java @@ -16,6 +16,7 @@ package com.android.overlaytest; +import static android.content.res.Flags.FLAG_SELF_TARGETING_ANDROID_RESOURCE_FRRO; import static android.content.Context.MODE_PRIVATE; import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH; @@ -41,6 +42,8 @@ import android.os.FabricatedOverlayInternal; import android.os.FabricatedOverlayInternalEntry; import android.os.ParcelFileDescriptor; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.Log; import android.util.Pair; import android.util.TypedValue; @@ -76,6 +79,8 @@ import java.util.List; */ @RunWith(AndroidJUnit4.class) public class OverlayManagerImplTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final String TAG = "OverlayManagerImplTest"; private static final String TARGET_COLOR_RES = "color/mycolor"; @@ -210,6 +215,22 @@ public class OverlayManagerImplTest { } @Test + @DisableFlags(FLAG_SELF_TARGETING_ANDROID_RESOURCE_FRRO) + public void registerOverlay_forAndroidPackage_shouldFail() { + FabricatedOverlayInternal overlayInternal = + createOverlayWithName( + mOverlayName, + SYSTEM_APP_OVERLAYABLE, + "android", + List.of(Pair.create("color/white", Pair.create(null, Color.BLACK)))); + + assertThrows( + "Wrong target package name", + IllegalArgumentException.class, + () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal)); + } + + @Test public void getOverlayInfosForTarget_defaultShouldBeZero() { List<OverlayInfo> overlayInfos = mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()); diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp index 634098074cca..9b7200436f02 100644 --- a/core/tests/overlaytests/host/Android.bp +++ b/core/tests/overlaytests/host/Android.bp @@ -28,14 +28,14 @@ java_test_host { test_suites: [ "device-tests", ], - target_required: [ - "OverlayHostTests_NonPlatformSignatureOverlay", - "OverlayHostTests_PlatformSignatureStaticOverlay", - "OverlayHostTests_PlatformSignatureOverlay", - "OverlayHostTests_UpdateOverlay", - "OverlayHostTests_FrameworkOverlayV1", - "OverlayHostTests_FrameworkOverlayV2", - "OverlayHostTests_AppOverlayV1", - "OverlayHostTests_AppOverlayV2", + device_common_data: [ + ":OverlayHostTests_NonPlatformSignatureOverlay", + ":OverlayHostTests_PlatformSignatureStaticOverlay", + ":OverlayHostTests_PlatformSignatureOverlay", + ":OverlayHostTests_UpdateOverlay", + ":OverlayHostTests_FrameworkOverlayV1", + ":OverlayHostTests_FrameworkOverlayV2", + ":OverlayHostTests_AppOverlayV1", + ":OverlayHostTests_AppOverlayV2", ], } 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/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 9ea2943bc6da..f0613cec6a0b 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -398,27 +398,23 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { new TaskFragmentAnimationParams.Builder(); final int animationBackgroundColor = getAnimationBackgroundColor(splitAttributes); builder.setAnimationBackgroundColor(animationBackgroundColor); - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - final int openAnimationResId = - splitAttributes.getAnimationParams().getOpenAnimationResId(); - builder.setOpenAnimationResId(openAnimationResId); - final int closeAnimationResId = - splitAttributes.getAnimationParams().getCloseAnimationResId(); - builder.setCloseAnimationResId(closeAnimationResId); - final int changeAnimationResId = - splitAttributes.getAnimationParams().getChangeAnimationResId(); - builder.setChangeAnimationResId(changeAnimationResId); - } + final int openAnimationResId = + splitAttributes.getAnimationParams().getOpenAnimationResId(); + builder.setOpenAnimationResId(openAnimationResId); + final int closeAnimationResId = + splitAttributes.getAnimationParams().getCloseAnimationResId(); + builder.setCloseAnimationResId(closeAnimationResId); + final int changeAnimationResId = + splitAttributes.getAnimationParams().getChangeAnimationResId(); + builder.setChangeAnimationResId(changeAnimationResId); return builder.build(); } @ColorInt private static int getAnimationBackgroundColor(@NonNull SplitAttributes splitAttributes) { int animationBackgroundColor = DEFAULT_ANIMATION_BACKGROUND_COLOR; - AnimationBackground animationBackground = splitAttributes.getAnimationBackground(); - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - animationBackground = splitAttributes.getAnimationParams().getAnimationBackground(); - } + final AnimationBackground animationBackground = + splitAttributes.getAnimationParams().getAnimationBackground(); if (animationBackground instanceof AnimationBackground.ColorBackground colorBackground) { animationBackgroundColor = colorBackground.getColor(); } 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/res/color/bubble_drop_target_background_color.xml b/libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml index ab1ab984fd5f..87d36288cfd5 100644 --- a/libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml +++ b/libs/WindowManager/Shell/res/color/bubble_drop_target_background_color.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:alpha="0.35" android:color="?androidprv:attr/materialColorPrimaryContainer" /> + <item android:alpha="0.35" android:color="@androidprv:color/materialColorPrimaryContainer" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml index 640d184e641c..047f22fe0383 100644 --- a/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml +++ b/libs/WindowManager/Shell/res/color/desktop_mode_maximize_menu_button_color_selector.xml @@ -22,5 +22,5 @@ android:color="?androidprv:attr/colorAccentPrimary"/> <item android:state_selected="true" android:color="?androidprv:attr/colorAccentPrimary"/> - <item android:color="?androidprv:attr/materialColorOutlineVariant"/> + <item android:color="@androidprv:color/materialColorOutlineVariant"/> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/open_by_default_settings_dialog_radio_button_color.xml b/libs/WindowManager/Shell/res/color/open_by_default_settings_dialog_radio_button_color.xml index 0f9b28a07bde..9741b94f3ddb 100644 --- a/libs/WindowManager/Shell/res/color/open_by_default_settings_dialog_radio_button_color.xml +++ b/libs/WindowManager/Shell/res/color/open_by_default_settings_dialog_radio_button_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_checked="true" - android:color="?androidprv:attr/materialColorPrimaryContainer"/> - <item android:color="?androidprv:attr/materialColorSurfaceContainer"/> + android:color="@androidprv:color/materialColorPrimaryContainer"/> + <item android:color="@androidprv:color/materialColorSurfaceContainer"/> </selector> diff --git a/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml b/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml index b928a0b20764..20e00e1a9b90 100644 --- a/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml +++ b/libs/WindowManager/Shell/res/drawable/bubble_drop_target_background.xml @@ -21,6 +21,6 @@ <solid android:color="@color/bubble_drop_target_background_color" /> <stroke android:width="1dp" - android:color="?androidprv:attr/materialColorPrimaryContainer" /> + android:color="@androidprv:color/materialColorPrimaryContainer" /> </shape> </inset> diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml index 657720ee6088..5acca45654f0 100644 --- a/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml +++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_btn_bg.xml @@ -19,7 +19,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> <solid - android:color="?androidprv:attr/materialColorSurfaceContainerHigh" + android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <corners android:radius="18sp" /> diff --git a/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_bg.xml index 8fd2e68f6451..f4d1de89d7a3 100644 --- a/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_bg.xml +++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_bg.xml @@ -17,7 +17,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceBright" /> + <solid android:color="@androidprv:color/materialColorSurfaceBright" /> <corners android:bottomLeftRadius="?android:attr/dialogCornerRadius" android:topLeftRadius="?android:attr/dialogCornerRadius" diff --git a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_button_dark.xml deleted file mode 100644 index f3800e05148e..000000000000 --- a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_button_dark.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:height="24dp" - android:width="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="#000000" - android:pathData="M5,5H10V7H7V10H5V5M14,5H19V10H17V7H14V5M17,14H19V19H14V17H17V14M10,17V19H5V14H7V17H10Z"/> -</vector> diff --git a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_exit_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_or_maximize_exit_button_dark.xml index 5260450e8a13..b6289e2d6dd7 100644 --- a/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_exit_button_dark.xml +++ b/libs/WindowManager/Shell/res/drawable/decor_desktop_mode_immersive_or_maximize_exit_button_dark.xml @@ -21,6 +21,6 @@ android:viewportHeight="960" android:tint="?attr/colorControlNormal"> <path - android:fillColor="@android:color/white" - android:pathData="M240,840L240,720L120,720L120,640L320,640L320,840L240,840ZM640,840L640,640L840,640L840,720L720,720L720,840L640,840ZM120,320L120,240L240,240L240,120L320,120L320,320L120,320ZM640,320L640,120L720,120L720,240L840,240L840,320L640,320Z"/> + android:fillColor="@android:color/black" + android:pathData="M520,560L600,560L600,560ZM320,720Q287,720 263.5,696.5Q240,673 240,640L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,640Q880,673 856.5,696.5Q833,720 800,720L320,720ZM320,640L800,640Q800,640 800,640Q800,640 800,640L800,160Q800,160 800,160Q800,160 800,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640ZM160,880Q127,880 103.5,856.5Q80,833 80,800L80,240L160,240L160,800Q160,800 160,800Q160,800 160,800L720,800L720,880L160,880ZM320,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640L320,640Q320,640 320,640Q320,640 320,640L320,160Q320,160 320,160Q320,160 320,160Z"/> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml index 15837adc2c77..5769a851a8f0 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_handle_menu_background.xml @@ -18,5 +18,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <corners android:radius="@dimen/desktop_mode_handle_menu_corner_radius" /> - <solid android:color="?androidprv:attr/materialColorSurfaceBright" /> + <solid android:color="@androidprv:color/materialColorSurfaceBright" /> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml index 9566f2f140c7..bab2c9582089 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_background.xml @@ -17,6 +17,6 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerLow" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerLow" /> <corners android:radius="@dimen/desktop_mode_maximize_menu_corner_radius" /> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_layout_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_layout_background.xml index a30cfb74bf4a..b03b13427630 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_layout_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_maximize_menu_layout_background.xml @@ -20,6 +20,6 @@ android:shape="rectangle"> <corners android:radius="@dimen/desktop_mode_maximize_menu_buttons_outline_radius"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerLow"/> - <stroke android:width="1dp" android:color="?androidprv:attr/materialColorOutlineVariant"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerLow"/> + <stroke android:width="1dp" android:color="@androidprv:color/materialColorOutlineVariant"/> </shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_promo_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_promo_background.xml index 645d24df7c26..b24d432cece0 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_promo_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_windowing_education_promo_background.xml @@ -17,6 +17,6 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerLow" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerLow" /> <corners android:radius="@dimen/desktop_windowing_education_promo_corner_radius" /> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml index 4e673e65e053..dd1a1b1dca13 100644 --- a/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml +++ b/libs/WindowManager/Shell/res/drawable/desktop_windowing_transition_background.xml @@ -18,7 +18,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:id="@+id/indicator_solid"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimaryContainer" /> + <solid android:color="@androidprv:color/materialColorPrimaryContainer" /> <corners android:radius="28dp" /> </shape> </item> @@ -26,7 +26,7 @@ <shape android:shape="rectangle"> <corners android:radius="28dp" /> <stroke android:width="1dp" - android:color="?androidprv:attr/materialColorPrimaryContainer"/> + android:color="@androidprv:color/materialColorPrimaryContainer"/> </shape> </item> </layer-list> diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml index f37fb8dbe118..527cc31f2f76 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dialog_background.xml @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh"/> <corners android:radius="@dimen/letterbox_education_dialog_corner_radius"/> </shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml index 3fdd059ca982..5336b3a22897 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_dismiss_button_background_ripple.xml @@ -32,7 +32,7 @@ </item> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimary"/> + <solid android:color="@androidprv:color/materialColorPrimary"/> <corners android:radius="@dimen/letterbox_education_dialog_button_radius"/> <padding android:left="@dimen/letterbox_education_dialog_horizontal_padding" android:top="@dimen/letterbox_education_dialog_vertical_padding" diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml index 67929dfc5f71..f45d7044423f 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml @@ -25,6 +25,6 @@ android:pathData="M0,0h32v32h-32z"/> <path android:pathData="M5.867,22.667C4.489,21.844 3.389,20.733 2.567,19.333C1.744,17.933 1.333,16.378 1.333,14.667C1.333,12.067 2.233,9.867 4.033,8.067C5.856,6.244 8.067,5.333 10.667,5.333C13.267,5.333 15.467,6.244 17.267,8.067C19.089,9.867 20,12.067 20,14.667C20,16.378 19.589,17.933 18.767,19.333C17.944,20.733 16.844,21.844 15.467,22.667H5.867ZM6.667,20H14.667C15.511,19.356 16.167,18.578 16.633,17.667C17.1,16.733 17.333,15.733 17.333,14.667C17.333,12.822 16.678,11.256 15.367,9.967C14.078,8.656 12.511,8 10.667,8C8.822,8 7.244,8.656 5.933,9.967C4.644,11.256 4,12.822 4,14.667C4,15.733 4.233,16.733 4.7,17.667C5.167,18.578 5.822,19.356 6.667,20ZM7.2,26.667C6.822,26.667 6.5,26.544 6.233,26.3C5.989,26.033 5.867,25.711 5.867,25.333C5.867,24.956 5.989,24.644 6.233,24.4C6.5,24.133 6.822,24 7.2,24H14.133C14.511,24 14.822,24.133 15.067,24.4C15.333,24.644 15.467,24.956 15.467,25.333C15.467,25.711 15.333,26.033 15.067,26.3C14.822,26.544 14.511,26.667 14.133,26.667H7.2ZM10.667,30.667C9.933,30.667 9.3,30.411 8.767,29.9C8.256,29.367 8,28.733 8,28H13.333C13.333,28.733 13.067,29.367 12.533,29.9C12.022,30.411 11.4,30.667 10.667,30.667ZM24.667,13.367C24.667,11.7 24.078,10.278 22.9,9.1C21.722,7.922 20.3,7.333 18.633,7.333C20.3,7.333 21.722,6.756 22.9,5.6C24.078,4.422 24.667,3 24.667,1.333C24.667,3 25.244,4.422 26.4,5.6C27.578,6.756 29,7.333 30.667,7.333C29,7.333 27.578,7.922 26.4,9.1C25.244,10.278 24.667,11.7 24.667,13.367Z" - android:fillColor="?androidprv:attr/materialColorPrimary"/> + android:fillColor="@androidprv:color/materialColorPrimary"/> </group> </vector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml index 4207482260ba..4e77720bd18d 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_button_background_ripple.xml @@ -32,7 +32,7 @@ </item> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimary"/> + <solid android:color="@androidprv:color/materialColorPrimary"/> <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> <padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding" android:top="@dimen/letterbox_restart_dialog_vertical_padding" diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml index 72cfeefceffb..90b314a58b8f 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dialog_background.xml @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh"/> <corners android:radius="@dimen/letterbox_restart_dialog_corner_radius"/> </shape>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml index 816b35063b00..d64e63261ac9 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_dismiss_button_background_ripple.xml @@ -32,9 +32,9 @@ </item> <item> <shape android:shape="rectangle"> - <stroke android:color="?androidprv:attr/materialColorOutlineVariant" + <stroke android:color="@androidprv:color/materialColorOutlineVariant" android:width="1dp"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh"/> <corners android:radius="@dimen/letterbox_restart_dialog_button_radius"/> <padding android:left="@dimen/letterbox_restart_dialog_horizontal_padding" android:top="@dimen/letterbox_restart_dialog_vertical_padding" diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml index f13d26c7f89e..53b4a4b70ed3 100644 --- a/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml +++ b/libs/WindowManager/Shell/res/drawable/letterbox_restart_header_ic_arrows.xml @@ -25,6 +25,6 @@ android:pathData="M0,0h32v32h-32z"/> <path android:pathData="M8.533,25.333H10.667C11.044,25.333 11.356,25.467 11.6,25.733C11.867,25.978 12,26.289 12,26.667C12,27.044 11.867,27.367 11.6,27.633C11.356,27.878 11.044,28 10.667,28H5.333C4.956,28 4.633,27.878 4.367,27.633C4.122,27.367 4,27.044 4,26.667V21.333C4,20.956 4.122,20.644 4.367,20.4C4.633,20.133 4.956,20 5.333,20C5.711,20 6.022,20.133 6.267,20.4C6.533,20.644 6.667,20.956 6.667,21.333V23.467L9.867,20.267C10.111,20.022 10.422,19.9 10.8,19.9C11.178,19.9 11.489,20.022 11.733,20.267C11.978,20.511 12.1,20.822 12.1,21.2C12.1,21.578 11.978,21.889 11.733,22.133L8.533,25.333ZM23.467,25.333L20.267,22.133C20.022,21.889 19.9,21.578 19.9,21.2C19.9,20.822 20.022,20.511 20.267,20.267C20.511,20.022 20.822,19.9 21.2,19.9C21.578,19.9 21.889,20.022 22.133,20.267L25.333,23.467V21.333C25.333,20.956 25.456,20.644 25.7,20.4C25.967,20.133 26.289,20 26.667,20C27.044,20 27.356,20.133 27.6,20.4C27.867,20.644 28,20.956 28,21.333V26.667C28,27.044 27.867,27.367 27.6,27.633C27.356,27.878 27.044,28 26.667,28H21.333C20.956,28 20.633,27.878 20.367,27.633C20.122,27.367 20,27.044 20,26.667C20,26.289 20.122,25.978 20.367,25.733C20.633,25.467 20.956,25.333 21.333,25.333H23.467ZM6.667,8.533V10.667C6.667,11.044 6.533,11.367 6.267,11.633C6.022,11.878 5.711,12 5.333,12C4.956,12 4.633,11.878 4.367,11.633C4.122,11.367 4,11.044 4,10.667V5.333C4,4.956 4.122,4.644 4.367,4.4C4.633,4.133 4.956,4 5.333,4H10.667C11.044,4 11.356,4.133 11.6,4.4C11.867,4.644 12,4.956 12,5.333C12,5.711 11.867,6.033 11.6,6.3C11.356,6.544 11.044,6.667 10.667,6.667H8.533L11.733,9.867C11.978,10.111 12.1,10.422 12.1,10.8C12.1,11.178 11.978,11.489 11.733,11.733C11.489,11.978 11.178,12.1 10.8,12.1C10.422,12.1 10.111,11.978 9.867,11.733L6.667,8.533ZM25.333,8.533L22.133,11.733C21.889,11.978 21.578,12.1 21.2,12.1C20.822,12.1 20.511,11.978 20.267,11.733C20.022,11.489 19.9,11.178 19.9,10.8C19.9,10.422 20.022,10.111 20.267,9.867L23.467,6.667H21.333C20.956,6.667 20.633,6.544 20.367,6.3C20.122,6.033 20,5.711 20,5.333C20,4.956 20.122,4.644 20.367,4.4C20.633,4.133 20.956,4 21.333,4H26.667C27.044,4 27.356,4.133 27.6,4.4C27.867,4.644 28,4.956 28,5.333V10.667C28,11.044 27.867,11.367 27.6,11.633C27.356,11.878 27.044,12 26.667,12C26.289,12 25.967,11.878 25.7,11.633C25.456,11.367 25.333,11.044 25.333,10.667V8.533Z" - android:fillColor="?androidprv:attr/materialColorPrimary"/> + android:fillColor="@androidprv:color/materialColorPrimary"/> </group> </vector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_background.xml b/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_background.xml index 4eb22712f5e1..d1a510a03674 100644 --- a/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_background.xml +++ b/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_background.xml @@ -17,6 +17,6 @@ <shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainer"/> <corners android:radius="28dp"/> </shape> diff --git a/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml b/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml index 2b2e9df07dce..20e2e7e5a832 100644 --- a/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml +++ b/libs/WindowManager/Shell/res/drawable/open_by_default_settings_dialog_confirm_button_background.xml @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimary"/> + <solid android:color="@androidprv:color/materialColorPrimary"/> <corners android:radius="50dp"/> </shape> diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml index 4c7d1c7339fb..7347fbad5f5d 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml @@ -29,7 +29,7 @@ <ImageView android:layout_width="@dimen/bubble_popup_icon_size" android:layout_height="@dimen/bubble_popup_icon_size" - android:tint="?androidprv:attr/materialColorOutline" + android:tint="@androidprv:color/materialColorOutline" android:contentDescription="@null" android:src="@drawable/pip_ic_settings"/> @@ -41,7 +41,7 @@ android:maxLines="1" android:ellipsize="end" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:text="@string/bubble_bar_education_manage_title"/> <TextView @@ -51,7 +51,7 @@ android:paddingBottom="@dimen/bubble_popup_padding_bottom" android:maxWidth="@dimen/bubble_popup_content_max_width" android:textAppearance="@android:style/TextAppearance.DeviceDefault" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textAlignment="center" android:text="@string/bubble_bar_education_manage_text"/> diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml index e3217811ca29..5750ed7bf8d6 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_item.xml @@ -36,7 +36,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault" /> </com.android.wm.shell.bubbles.bar.BubbleBarMenuItemView>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml index 7aca921dccc7..27e3b006b961 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml @@ -50,7 +50,7 @@ android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_weight="1" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault" /> <ImageView @@ -60,7 +60,7 @@ android:layout_marginStart="8dp" android:contentDescription="@null" android:src="@drawable/ic_expand_less" - app:tint="?androidprv:attr/materialColorOnSurface" /> + app:tint="@androidprv:color/materialColorOnSurface" /> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml index 345c399652f9..f0e1871168dd 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_bar_stack_education.xml @@ -29,7 +29,7 @@ <ImageView android:layout_width="@dimen/bubble_popup_icon_size" android:layout_height="@dimen/bubble_popup_icon_size" - android:tint="?androidprv:attr/materialColorOutline" + android:tint="@androidprv:color/materialColorOutline" android:contentDescription="@null" android:src="@drawable/ic_floating_landscape"/> @@ -41,7 +41,7 @@ android:maxLines="1" android:ellipsize="end" android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:text="@string/bubble_bar_education_stack_title"/> <TextView @@ -51,7 +51,7 @@ android:paddingBottom="@dimen/bubble_popup_padding_bottom" android:maxWidth="@dimen/bubble_popup_content_max_width" android:textAppearance="@android:style/TextAppearance.DeviceDefault" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textAlignment="center" android:text="@string/bubble_bar_education_stack_text"/> diff --git a/libs/WindowManager/Shell/res/layout/bubble_flyout.xml b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml index 65a07a718677..deabd564d80a 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_flyout.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml @@ -49,7 +49,7 @@ android:fontFamily="@*android:string/config_bodyFontFamilyMedium" android:maxLines="1" android:ellipsize="end" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> <TextView @@ -59,7 +59,7 @@ android:fontFamily="@*android:string/config_bodyFontFamily" android:maxLines="2" android:ellipsize="end" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml index f88d63d796ea..0c446df69563 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml @@ -28,6 +28,6 @@ android:focusable="true" android:text="@string/manage_bubbles_text" android:textSize="@*android:dimen/text_size_body_2_material" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:background="@drawable/bubble_manage_btn_bg" />
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml index d8ae9c8c64a6..4daaf9c6b57f 100644 --- a/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml +++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml @@ -43,7 +43,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault" android:text="@string/bubble_dismiss_text" /> @@ -70,7 +70,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault" android:text="@string/bubbles_dont_bubble_conversation" /> @@ -98,7 +98,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="@*android:style/TextAppearance.DeviceDefault" /> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index bfd9c818a96e..b69563b46e06 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -52,7 +52,7 @@ android:layout_height="wrap_content" tools:text="Gmail" android:importantForAccessibility="no" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="14sp" android:textFontWeight="500" android:lineHeight="20dp" @@ -69,7 +69,7 @@ android:contentDescription="@string/collapse_menu_text" android:src="@drawable/ic_baseline_expand_more_24" android:rotation="180" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:background="?android:selectableItemBackgroundBorderless"/> </LinearLayout> @@ -89,7 +89,7 @@ android:layout_marginEnd="4dp" android:contentDescription="@string/fullscreen_text" android:src="@drawable/desktop_mode_ic_handle_menu_fullscreen" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> @@ -99,7 +99,7 @@ android:layout_marginEnd="4dp" android:contentDescription="@string/split_screen_text" android:src="@drawable/desktop_mode_ic_handle_menu_splitscreen" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> @@ -109,7 +109,7 @@ android:layout_marginEnd="4dp" android:contentDescription="@string/float_button_text" android:src="@drawable/desktop_mode_ic_handle_menu_floating" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> @@ -118,7 +118,7 @@ android:layout_marginStart="4dp" android:contentDescription="@string/desktop_text" android:src="@drawable/desktop_mode_ic_handle_menu_desktop" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:layout_weight="1" style="@style/DesktopModeHandleMenuWindowingButton"/> @@ -139,7 +139,7 @@ android:contentDescription="@string/screenshot_text" android:text="@string/screenshot_text" android:drawableStart="@drawable/desktop_mode_ic_handle_menu_screenshot" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton"/> <Button @@ -147,7 +147,7 @@ android:contentDescription="@string/new_window_text" android:text="@string/new_window_text" android:drawableStart="@drawable/desktop_mode_ic_handle_menu_new_window" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton" /> <Button @@ -155,7 +155,7 @@ android:contentDescription="@string/manage_windows_text" android:text="@string/manage_windows_text" android:drawableStart="@drawable/desktop_mode_ic_handle_menu_manage_windows" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton" /> <Button @@ -163,7 +163,7 @@ android:contentDescription="@string/change_aspect_ratio_text" android:text="@string/change_aspect_ratio_text" android:drawableStart="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton" /> </LinearLayout> @@ -183,7 +183,7 @@ android:contentDescription="@string/open_in_browser_text" android:text="@string/open_in_browser_text" android:drawableStart="@drawable/desktop_mode_ic_handle_menu_open_in_browser" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" style="@style/DesktopModeHandleMenuActionButton"/> <ImageButton @@ -195,7 +195,7 @@ android:layout_marginStart="10dp" android:contentDescription="@string/open_by_default_settings_text" android:src="@drawable/desktop_mode_ic_handle_menu_open_by_default_settings" - android:tint="?androidprv:attr/materialColorOnSurface"/> + android:tint="@androidprv:color/materialColorOnSurface"/> </LinearLayout> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml index 375968ab0ad2..8d7e5fd95957 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml @@ -58,7 +58,7 @@ android:fontFamily="google-sans-text" android:importantForAccessibility="no" android:text="@string/desktop_mode_maximize_menu_immersive_button_text" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:alpha="0"/> </LinearLayout> @@ -89,7 +89,7 @@ android:fontFamily="google-sans-text" android:importantForAccessibility="no" android:text="@string/desktop_mode_maximize_menu_maximize_text" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:alpha="0"/> </LinearLayout> @@ -140,7 +140,7 @@ android:importantForAccessibility="no" android:fontFamily="google-sans-text" android:text="@string/desktop_mode_maximize_menu_snap_text" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:alpha="0"/> </LinearLayout> </LinearLayout> diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml index bda087b143d0..0a44cd42e790 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml @@ -37,7 +37,7 @@ android:layout_height="wrap_content" android:lineSpacingExtra="4sp" android:textAlignment="center" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="14sp"/> </LinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml index 488123ad7b0c..cd36983aff2d 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml @@ -64,7 +64,7 @@ android:lineSpacingExtra="4sp" android:text="@string/letterbox_education_dialog_title" android:textAlignment="center" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:fontFamily="@*android:string/config_headlineFontFamily" android:textSize="24sp"/> @@ -104,7 +104,7 @@ android:background= "@drawable/letterbox_education_dismiss_button_background_ripple" android:text="@string/letterbox_education_got_it" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" android:textAlignment="center" android:contentDescription="@string/letterbox_education_got_it"/> diff --git a/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml b/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml index b5bceda9a623..f6256e6bc5e7 100644 --- a/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml +++ b/libs/WindowManager/Shell/res/layout/open_by_default_settings_dialog.xml @@ -64,7 +64,7 @@ android:lineHeight="32dp" android:textFontWeight="400" android:textSize="24sp" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" tools:text="Gmail" /> <TextView @@ -75,7 +75,7 @@ android:lineHeight="16dp" android:layout_gravity="center_horizontal" android:layout_marginBottom="16dp" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:text="@string/open_by_default_dialog_subheader_text"/> <RadioGroup @@ -121,7 +121,7 @@ android:layout_marginBottom="24dp" android:textSize="14sp" android:textFontWeight="500" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" android:background="@drawable/open_by_default_settings_dialog_confirm_button_background"/> </LinearLayout> </ScrollView> diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index b7aa1581a5c1..d754243a2b07 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -43,7 +43,7 @@ <color name="compat_controls_text">@android:color/system_neutral1_50</color> <!-- Letterbox Education --> - <color name="letterbox_education_text_secondary">?androidprv:attr/materialColorSecondary</color> + <color name="letterbox_education_text_secondary">@androidprv:color/materialColorSecondary</color> <!-- Letterbox Dialog --> <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index 597a921302b7..8a4a7023b8e8 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -48,7 +48,7 @@ <item name="android:paddingEnd">0dp</item> <item name="android:textSize">14sp</item> <item name="android:textFontWeight">500</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:drawablePadding">16dp</item> <item name="android:background">?android:selectableItemBackground</item> </style> @@ -92,7 +92,7 @@ <style name="RestartDialogTitleText"> <item name="android:textSize">24sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:lineSpacingExtra">8sp</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> </style> @@ -104,23 +104,23 @@ <style name="RestartDialogBodyText" parent="RestartDialogBodyStyle"> <item name="android:letterSpacing">0.02</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:lineSpacingExtra">6sp</item> </style> <style name="RestartDialogCheckboxText" parent="RestartDialogBodyStyle"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:lineSpacingExtra">6sp</item> </style> <style name="RestartDialogDismissButton" parent="RestartDialogBodyStyle"> <item name="android:lineSpacingExtra">2sp</item> - <item name="android:textColor">?androidprv:attr/materialColorPrimary</item> + <item name="android:textColor">@androidprv:color/materialColorPrimary</item> </style> <style name="RestartDialogConfirmButton" parent="RestartDialogBodyStyle"> <item name="android:lineSpacingExtra">2sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimary</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimary</item> </style> <style name="ReachabilityEduHandLayout" parent="Theme.AppCompat.Light"> diff --git a/libs/WindowManager/Shell/shared/Android.bp b/libs/WindowManager/Shell/shared/Android.bp index 5113d980fb7d..5bbda95c466f 100644 --- a/libs/WindowManager/Shell/shared/Android.bp +++ b/libs/WindowManager/Shell/shared/Android.bp @@ -26,6 +26,7 @@ filegroup { name: "wm_shell-shared-utils", srcs: [ "src/com/android/wm/shell/shared/TransitionUtil.java", + "src/com/android/wm/shell/shared/Utils.java", ], } @@ -71,6 +72,7 @@ java_library { srcs: [ "**/desktopmode/*.java", "**/desktopmode/*.kt", + ":wm_shell-shared-utils", ], static_libs: [ "com.android.window.flags.window-aconfig-java", diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java new file mode 100644 index 000000000000..e19027a352f7 --- /dev/null +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.shared; + +import android.annotation.NonNull; + +import java.util.function.Supplier; + +/** + * This class provides generic utility methods and classes for shell + */ +public class Utils { + + /** + * Lazily returns object from a supplier with caching + * @param <T> type of object to get + */ + public static class Lazy<T> { + private T mInstance; + + /** + * @param supplier the supplier to use, when the instance has not yet been initialized + * @return the cached value or the value from the supplier + */ + public final T get(@NonNull Supplier<T> supplier) { + if (mInstance == null) { + mInstance = supplier.get(); + } + return mInstance; + } + } +} 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..a5d698aff2a2 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 @@ -16,16 +16,23 @@ package com.android.wm.shell.shared.desktopmode; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import android.annotation.NonNull; import android.content.Context; +import android.hardware.display.DisplayManager; import android.os.SystemProperties; +import android.view.Display; +import android.view.WindowManager; import android.window.DesktopModeFlags; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.window.flags.Flags; +import com.android.wm.shell.shared.Utils.Lazy; import java.io.PrintWriter; +import java.util.Arrays; /** * Constants for desktop mode feature @@ -35,6 +42,8 @@ public class DesktopModeStatus { private static final String TAG = "DesktopModeStatus"; + private static Lazy<Boolean> sIsLargeScreenDevice = new Lazy<>(); + /** * Flag to indicate whether task resizing is veiled. */ @@ -91,6 +100,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 +134,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 +182,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 @@ -195,13 +236,12 @@ public class DesktopModeStatus { * necessarily enabling desktop mode */ public static boolean overridesShowAppHandle(@NonNull Context context) { - return Flags.showAppHandleLargeScreens() - && context.getResources().getBoolean(R.bool.config_enableAppHandle); + return Flags.showAppHandleLargeScreens() && deviceHasLargeScreen(context); } /** * @return {@code true} if the app handle should be shown because desktop mode is enabled or - * the device is overriding {@code R.bool.config_enableAppHandle} + * the device has a large screen */ public static boolean canEnterDesktopModeOrShowAppHandle(@NonNull Context context) { return canEnterDesktopMode(context) || overridesShowAppHandle(context); @@ -244,6 +284,18 @@ public class DesktopModeStatus { } /** + * @return {@code true} if this device has an internal large screen + */ + private static boolean deviceHasLargeScreen(@NonNull Context context) { + return sIsLargeScreenDevice.get(() -> Arrays.stream( + context.getSystemService(DisplayManager.class) + .getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .filter(display -> display.getType() == Display.TYPE_INTERNAL) + .anyMatch(display -> display.getMinSizeDimensionDp() + >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP)); + } + + /** * Return {@code true} if a display should enter desktop mode by default when the windowing mode * of the display's root [TaskDisplayArea] is set to WINDOWING_MODE_FREEFORM. */ @@ -283,6 +335,6 @@ public class DesktopModeStatus { pw.println(maxTaskLimitHandle == null ? "null" : maxTaskLimitHandle.getInt(/* def= */ -1)); pw.print(innerPrefix); pw.print("showAppHandle config override="); - pw.print(context.getResources().getBoolean(R.bool.config_enableAppHandle)); + pw.print(overridesShowAppHandle(context)); } } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java index f9f43bc8dfae..86be0d4a4ea5 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/split/SplitScreenConstants.java @@ -159,7 +159,8 @@ public class SplitScreenConstants { * {@link PersistentSnapPosition} + {@link #NOT_IN_SPLIT}. */ @IntDef(value = { - NOT_IN_SPLIT, + NOT_IN_SPLIT, // user is not in split screen + SNAP_TO_NONE, // in "free snap mode," where apps are fully resizable SNAP_TO_2_33_66, SNAP_TO_2_50_50, SNAP_TO_2_66_33, @@ -171,6 +172,23 @@ public class SplitScreenConstants { }) public @interface SplitScreenState {} + /** Converts a {@link SplitScreenState} to a human-readable string. */ + public static String stateToString(@SplitScreenState int state) { + return switch (state) { + case NOT_IN_SPLIT -> "NOT_IN_SPLIT"; + case SNAP_TO_NONE -> "SNAP_TO_NONE"; + case SNAP_TO_2_33_66 -> "SNAP_TO_2_33_66"; + case SNAP_TO_2_50_50 -> "SNAP_TO_2_50_50"; + case SNAP_TO_2_66_33 -> "SNAP_TO_2_66_33"; + case SNAP_TO_2_90_10 -> "SNAP_TO_2_90_10"; + case SNAP_TO_2_10_90 -> "SNAP_TO_2_10_90"; + case SNAP_TO_3_33_33_33 -> "SNAP_TO_3_33_33_33"; + case SNAP_TO_3_45_45_10 -> "SNAP_TO_3_45_45_10"; + case SNAP_TO_3_10_45_45 -> "SNAP_TO_3_10_45_45"; + default -> "UNKNOWN"; + }; + } + /** * Checks if the snapPosition in question is a {@link PersistentSnapPosition}. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index d2cef4baf798..f269b3831aab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -268,10 +268,7 @@ class ActivityEmbeddingAnimationRunner { final Animation animation = animationProvider.get(info, change, openingWholeScreenBounds); if (shouldUseJumpCutForAnimation(animation)) { - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - return new ArrayList<>(); - } - continue; + return new ArrayList<>(); } final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, animation, openingWholeScreenBounds); @@ -296,10 +293,7 @@ class ActivityEmbeddingAnimationRunner { final Animation animation = animationProvider.get(info, change, closingWholeScreenBounds); if (shouldUseJumpCutForAnimation(animation)) { - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - return new ArrayList<>(); - } - continue; + return new ArrayList<>(); } final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter( info, change, animation, closingWholeScreenBounds); @@ -455,11 +449,9 @@ class ActivityEmbeddingAnimationRunner { final Animation[] animations = mAnimationSpec.createChangeBoundsChangeAnimations(info, change, parentBounds); // Jump cut if either animation has zero for duration. - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - for (Animation animation : animations) { - if (shouldUseJumpCutForAnimation(animation)) { - return new ArrayList<>(); - } + for (Animation animation : animations) { + if (shouldUseJumpCutForAnimation(animation)) { + return new ArrayList<>(); } } // Keep track as we might need to add background color for the animation. @@ -516,10 +508,8 @@ class ActivityEmbeddingAnimationRunner { mAnimationSpec.createChangeBoundsOpenAnimation(info, change, parentBounds); shouldShowBackgroundColor = false; } - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - if (shouldUseJumpCutForAnimation(animation)) { - return new ArrayList<>(); - } + if (shouldUseJumpCutForAnimation(animation)) { + return new ArrayList<>(); } adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change, TransitionUtil.getRootFor(change, info))); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java index 3046307702c2..77799e99607b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java @@ -96,11 +96,9 @@ class ActivityEmbeddingAnimationSpec { @NonNull Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); - if (customAnimation != null) { - return customAnimation; - } + final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + if (customAnimation != null) { + return customAnimation; } // Use end bounds for opening. final Rect bounds = change.getEndAbsBounds(); @@ -130,11 +128,9 @@ class ActivityEmbeddingAnimationSpec { @NonNull Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); - if (customAnimation != null) { - return customAnimation; - } + final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + if (customAnimation != null) { + return customAnimation; } // Use start bounds for closing. final Rect bounds = change.getStartAbsBounds(); @@ -168,14 +164,12 @@ class ActivityEmbeddingAnimationSpec { @NonNull Animation[] createChangeBoundsChangeAnimations(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) { - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - // TODO(b/293658614): Support more complicated animations that may need more than a noop - // animation as the start leash. - final Animation noopAnimation = createNoopAnimation(change); - final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); - if (customAnimation != null) { - return new Animation[]{noopAnimation, customAnimation}; - } + // TODO(b/293658614): Support more complicated animations that may need more than a noop + // animation as the start leash. + final Animation noopAnimation = createNoopAnimation(change); + final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE); + if (customAnimation != null) { + return new Animation[]{noopAnimation, customAnimation}; } // Both start bounds and end bounds are in screen coordinates. We will post translate // to the local coordinates in ActivityEmbeddingAnimationAdapter#onAnimationUpdate @@ -320,13 +314,9 @@ class ActivityEmbeddingAnimationSpec { } final Animation anim; - if (Flags.activityEmbeddingAnimationCustomizationFlag()) { - // TODO(b/293658614): Consider allowing custom animations from non-default packages. - // Enforce limiting to animations from the default "android" package for now. - anim = mTransitionAnimation.loadDefaultAnimationRes(resId); - } else { - anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(), resId); - } + // TODO(b/293658614): Consider allowing custom animations from non-default packages. + // Enforce limiting to animations from the default "android" package for now. + anim = mTransitionAnimation.loadDefaultAnimationRes(resId); if (anim != null) { return anim; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt index 7243ea36b137..68c42d6a2648 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt @@ -18,6 +18,8 @@ package com.android.wm.shell.apptoweb +import android.app.assist.AssistContent +import android.app.assist.AssistContent.EXTRA_SESSION_TRANSFER_WEB_URI import android.content.Context import android.content.Intent import android.content.Intent.ACTION_VIEW @@ -102,3 +104,10 @@ fun getDomainVerificationUserState( return null } } + +/** + * Returns the web uri from the given [AssistContent]. + */ +fun AssistContent.getSessionWebUri(): Uri? { + return extras.getParcelable(EXTRA_SESSION_TRANSFER_WEB_URI) ?: webUri +} 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 c024840498ad..56efdb885512 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); @@ -731,6 +735,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont callback.onBackStarted(backEvent); if (mBackTransitionHandler.canHandOffAnimation()) { callback.setHandoffHandler(mHandoffHandler); + } else { + callback.setHandoffHandler(null); } mOnBackStartDispatched = true; } catch (RemoteException e) { @@ -1273,14 +1279,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, @NonNull Transitions.TransitionFinishCallback finishCallback) { - final boolean isPrepareTransition = - info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION; - if (isPrepareTransition) { - if (checkTakeoverFlags()) { - mTakeoverHandler = mTransitions.getHandlerForTakeover(transition, info); - } - kickStartAnimation(); - } // Both mShellExecutor and Transitions#mMainExecutor are ShellMainThread, so we don't // need to post to ShellExecutor when called. if (info.getType() == WindowManager.TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION) { @@ -1308,14 +1306,19 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont // animation never start, consume directly applyAndFinish(st, ft, finishCallback); return true; - } else if (mClosePrepareTransition == null && isPrepareTransition) { + } else if (mClosePrepareTransition == null + && info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION) { // Gesture animation was cancelled before prepare transition ready, create // the close prepare transition createClosePrepareTransition(); } } - if (handlePrepareTransition(info, st, ft, finishCallback)) { + if (handlePrepareTransition(transition, info, st, ft, finishCallback)) { + if (checkTakeoverFlags()) { + mTakeoverHandler = mTransitions.getHandlerForTakeover(transition, info); + } + kickStartAnimation(); return true; } return handleCloseTransition(info, st, ft, finishCallback); @@ -1627,7 +1630,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * happen when core make an activity become visible. */ @VisibleForTesting - boolean handlePrepareTransition( + boolean handlePrepareTransition(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, @@ -1675,6 +1678,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } } st.apply(); + // In case other transition handler took the handleRequest before this class. + mPrepareOpenTransition = transition; mFinishOpenTransaction = ft; mFinishOpenTransitionCallback = finishCallback; mOpenTransitionInfo = info; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 52955267a501..47032fd8616f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -38,7 +38,6 @@ import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; -import android.graphics.Color; import android.graphics.CornerPathEffect; import android.graphics.Outline; import android.graphics.Paint; @@ -543,15 +542,15 @@ public class BubbleExpandedView extends LinearLayout { void applyThemeAttrs() { final TypedArray ta = mContext.obtainStyledAttributes(new int[]{ - android.R.attr.dialogCornerRadius, - com.android.internal.R.attr.materialColorSurfaceBright, - com.android.internal.R.attr.materialColorSurfaceContainerHigh}); + android.R.attr.dialogCornerRadius}); boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows( mContext.getResources()); mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0; - mBackgroundColorFloating = ta.getColor(1, Color.WHITE); + mBackgroundColorFloating = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceBright); mExpandedViewContainer.setBackgroundColor(mBackgroundColorFloating); - final int manageMenuBg = ta.getColor(2, Color.WHITE); + final int manageMenuBg = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); ta.recycle(); if (mManageButton != null) { mManageButton.getBackground().setColorFilter(manageMenuBg, PorterDuff.Mode.SRC_IN); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java index 1711dca4a8a3..da6948d947d8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java @@ -28,7 +28,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Paint; @@ -209,7 +208,7 @@ public class BubbleFlyoutView extends FrameLayout { mPointerSize, mPointerSize, false /* isPointingLeft */)); mRightTriangleShape.setBounds(0, 0, mPointerSize, mPointerSize); - applyConfigurationColors(getResources().getConfiguration()); + applyConfigurationColors(); } @Override @@ -440,29 +439,23 @@ public class BubbleFlyoutView extends FrameLayout { boolean flagsChanged = nightModeFlags != mNightModeFlags; if (flagsChanged) { mNightModeFlags = nightModeFlags; - applyConfigurationColors(configuration); + applyConfigurationColors(); } return flagsChanged; } - private void applyConfigurationColors(Configuration configuration) { - int nightModeFlags = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; - boolean isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES; - try (TypedArray ta = mContext.obtainStyledAttributes( - new int[]{ - com.android.internal.R.attr.materialColorSurfaceContainer, - com.android.internal.R.attr.materialColorOnSurface, - com.android.internal.R.attr.materialColorOnSurfaceVariant})) { - mFloatingBackgroundColor = ta.getColor(0, - isNightModeOn ? Color.BLACK : Color.WHITE); - mSenderText.setTextColor(ta.getColor(1, - isNightModeOn ? Color.WHITE : Color.BLACK)); - mMessageText.setTextColor(ta.getColor(2, - isNightModeOn ? Color.WHITE : Color.BLACK)); - mBgPaint.setColor(mFloatingBackgroundColor); - mLeftTriangleShape.getPaint().setColor(mFloatingBackgroundColor); - mRightTriangleShape.getPaint().setColor(mFloatingBackgroundColor); - } + private void applyConfigurationColors() { + mFloatingBackgroundColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainer); + mSenderText.setTextColor( + mContext.getColor(com.android.internal.R.color.materialColorOnSurface)); + mMessageText.setTextColor( + mContext.getColor(com.android.internal.R.color.materialColorOnSurfaceVariant)); + + mBgPaint.setColor(mFloatingBackgroundColor); + mLeftTriangleShape.getPaint().setColor(mFloatingBackgroundColor); + mRightTriangleShape.getPaint().setColor(mFloatingBackgroundColor); + } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt index c74412b825d9..862906a11424 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt @@ -19,7 +19,6 @@ package com.android.wm.shell.bubbles import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.Context import android.graphics.Bitmap -import android.graphics.Color import android.graphics.Matrix import android.graphics.Path import android.graphics.drawable.AdaptiveIconDrawable @@ -117,18 +116,8 @@ class BubbleOverflow(private val context: Context, private val positioner: Bubbl val res = context.resources // Set overflow button accent color, dot color - - val typedArray = - context.obtainStyledAttributes( - intArrayOf( - com.android.internal.R.attr.materialColorPrimaryFixed, - com.android.internal.R.attr.materialColorOnPrimaryFixed - ) - ) - - val colorAccent = typedArray.getColor(0, Color.WHITE) - val shapeColor = typedArray.getColor(1, Color.BLACK) - typedArray.recycle() + val colorAccent = context.getColor(com.android.internal.R.color.materialColorPrimaryFixed) + val shapeColor = context.getColor(com.android.internal.R.color.materialColorOnPrimaryFixed) dotColor = colorAccent overflowBtn?.iconDrawable?.setTint(shapeColor) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java index bf98ef82b475..64f54b8ab5be 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java @@ -226,13 +226,11 @@ public class BubbleOverflowContainerView extends LinearLayout { ? res.getColor(R.color.bubbles_dark) : res.getColor(R.color.bubbles_light)); - final TypedArray typedArray = getContext().obtainStyledAttributes(new int[] { - com.android.internal.R.attr.materialColorSurfaceBright, - com.android.internal.R.attr.materialColorOnSurface}); - int bgColor = typedArray.getColor(0, isNightMode ? Color.BLACK : Color.WHITE); - int textColor = typedArray.getColor(1, isNightMode ? Color.WHITE : Color.BLACK); - textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, isNightMode); - typedArray.recycle(); + + int bgColor = getContext().getColor( + com.android.internal.R.color.materialColorSurfaceBright); + int textColor = getContext().getColor(com.android.internal.R.color.materialColorOnSurface); + setBackgroundColor(bgColor); mEmptyStateTitle.setTextColor(textColor); mEmptyStateSubtitle.setTextColor(textColor); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt index 9b3054e9ee13..a65466f71861 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt @@ -15,7 +15,6 @@ */ package com.android.wm.shell.bubbles -import android.graphics.Color import com.android.wm.shell.R import com.android.wm.shell.shared.bubbles.BubblePopupDrawable import com.android.wm.shell.shared.bubbles.BubblePopupView @@ -27,7 +26,6 @@ fun BubblePopupView.setup() { val attrs = context.obtainStyledAttributes( intArrayOf( - com.android.internal.R.attr.materialColorSurfaceContainer, android.R.attr.dialogCornerRadius ) ) @@ -35,8 +33,8 @@ fun BubblePopupView.setup() { val res = context.resources val config = BubblePopupDrawable.Config( - color = attrs.getColor(0, Color.WHITE), - cornerRadius = attrs.getDimension(1, 0f), + color = context.getColor(com.android.internal.R.color.materialColorSurfaceContainer), + cornerRadius = attrs.getDimension(0, 0f), contentPadding = res.getDimensionPixelSize(R.dimen.bubble_popup_padding), arrowWidth = res.getDimension(R.dimen.bubble_popup_arrow_width), arrowHeight = res.getDimension(R.dimen.bubble_popup_arrow_height), 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/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 88f55b8af8f7..249a218d5e56 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -40,7 +40,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.Outline; import android.graphics.PointF; import android.graphics.PorterDuff; @@ -1326,10 +1325,9 @@ public class BubbleStackView extends FrameLayout R.layout.bubble_manage_menu, this, false); mManageMenu.setVisibility(View.INVISIBLE); - final TypedArray ta = mContext.obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorSurfaceBright}); - final int menuBackgroundColor = ta.getColor(0, Color.WHITE); - ta.recycle(); + final int menuBackgroundColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceBright); + mManageMenu.getBackground().setColorFilter(menuBackgroundColor, PorterDuff.Mode.SRC_IN); PhysicsAnimator.getInstance(mManageMenu).setDefaultSpringConfig(mManageSpringConfig); 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/bubbles/bar/BubbleBarMenuItemView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java index 1c71ef415eae..6c14d83dfafa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuItemView.java @@ -17,7 +17,6 @@ package com.android.wm.shell.bubbles.bar; import android.annotation.ColorInt; import android.content.Context; -import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Icon; import android.util.AttributeSet; @@ -63,9 +62,8 @@ public class BubbleBarMenuItemView extends LinearLayout { */ void update(Icon icon, String title, @ColorInt int tint) { if (tint == Color.TRANSPARENT) { - final TypedArray typedArray = getContext().obtainStyledAttributes( - new int[]{com.android.internal.R.attr.materialColorOnSurface}); - mTextView.setTextColor(typedArray.getColor(0, Color.BLACK)); + mTextView.setTextColor( + getContext().getColor(com.android.internal.R.color.materialColorOnSurface)); } else { icon.setTint(tint); mTextView.setTextColor(tint); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java index 99e20097e61c..dfbf655bb6fc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java @@ -18,7 +18,6 @@ package com.android.wm.shell.bubbles.bar; import android.annotation.ColorInt; import android.content.Context; import android.content.res.ColorStateList; -import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Icon; import android.util.AttributeSet; @@ -91,14 +90,11 @@ public class BubbleBarMenuView extends LinearLayout { } private void updateThemeColors() { - try (TypedArray ta = mContext.obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorSurfaceBright, - com.android.internal.R.attr.materialColorOnSurface - })) { - mActionsSectionView.getBackground().setTint(ta.getColor(0, Color.WHITE)); - ImageViewCompat.setImageTintList(mBubbleDismissIconView, - ColorStateList.valueOf(ta.getColor(1, Color.BLACK))); - } + mActionsSectionView.getBackground().setTint( + mContext.getColor(com.android.internal.R.color.materialColorSurfaceBright)); + ImageViewCompat.setImageTintList(mBubbleDismissIconView, + ColorStateList.valueOf( + mContext.getColor(com.android.internal.R.color.materialColorOnSurface))); } /** Animates the menu from the specified start scale. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java index 9dd0cae20370..5f437d4af40f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java @@ -22,8 +22,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.drawable.Icon; import android.view.LayoutInflater; import android.view.View; @@ -169,12 +167,7 @@ class BubbleBarMenuViewController { int handleHeight = mHandleView.getHandleHeight(); float targetWidth = mHandleView.getHandleWidth() + widthDiff * WIDTH_SWAP_FRACTION; float targetHeight = targetWidth * mMenuView.getTitleItemHeight() / mMenuView.getWidth(); - int menuColor; - try (TypedArray ta = mContext.obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorSurfaceBright, - })) { - menuColor = ta.getColor(0, Color.WHITE); - } + int menuColor = mContext.getColor(com.android.internal.R.color.materialColorSurfaceBright); // Calculating deltas float swapScale = targetWidth / mMenuView.getWidth(); float handleWidthDelta = targetWidth - mHandleView.getHandleWidth(); @@ -227,11 +220,8 @@ class BubbleBarMenuViewController { private ArrayList<BubbleBarMenuView.MenuAction> createMenuActions(Bubble bubble) { ArrayList<BubbleBarMenuView.MenuAction> menuActions = new ArrayList<>(); Resources resources = mContext.getResources(); - int tintColor; - try (TypedArray ta = mContext.obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorOnSurface})) { - tintColor = ta.getColor(0, Color.TRANSPARENT); - } + int tintColor = mContext.getColor(com.android.internal.R.color.materialColorOnSurface); + if (bubble.isConversation()) { // Don't bubble conversation action menuActions.add(new BubbleBarMenuView.MenuAction( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/BoostExecutor.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/BoostExecutor.kt new file mode 100644 index 000000000000..498d0e406e4b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/BoostExecutor.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.common + +import android.os.Looper +import java.util.concurrent.Executor + +/** Executor implementation which can be boosted temporarily to a different thread priority. */ +interface BoostExecutor : Executor { + /** + * Requests that the executor is boosted until {@link #resetBoost()} is called. + */ + fun setBoost() {} + + /** + * Requests that the executor is not boosted (only resets if there are no other boost requests + * in progress). + */ + fun resetBoost() {} + + /** + * Returns whether the executor is boosted. + */ + fun isBoosted() : Boolean { + return false + } + + /** + * Returns the looper for this executor. + */ + fun getLooper() : Looper? { + return Looper.myLooper() + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index ec3c0b83fe2d..c74bf53268f9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -338,6 +338,11 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged // Make mImeSourceControl point to the new control before starting the animation. if (hadImeSourceControl && mImeSourceControl != imeSourceControl) { mImeSourceControl.release(SurfaceControl::release); + if (android.view.inputmethod.Flags.refactorInsetsController() + && !hasImeLeash && mAnimation != null) { + // In case of losing the leash, the animation should be cancelled. + mAnimation.cancel(); + } } mImeSourceControl = imeSourceControl; @@ -414,9 +419,14 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged // already (e.g., when focussing an editText in activity B, while and editText in // activity A is focussed), we will not get a call of #insetsControlChanged, and // therefore have to start the show animation from here - startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */); - - setVisibleDirectly(mImeRequestedVisible || mAnimation != null, statsToken); + startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */, + statsToken); + + // In case of a hide, the statsToken should not been send yet (as the animation + // is still ongoing). It will be sent at the end of the animation + boolean hideAnimOngoing = !mImeRequestedVisible && mAnimation != null; + setVisibleDirectly(mImeRequestedVisible || mAnimation != null, + hideAnimOngoing ? null : statsToken); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java index 736d954513b1..803f16ce39c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java @@ -16,15 +16,50 @@ package com.android.wm.shell.common; +import static android.os.Process.THREAD_PRIORITY_DEFAULT; +import static android.os.Process.setThreadPriority; + import android.annotation.NonNull; import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; + +import androidx.annotation.VisibleForTesting; + +import java.util.function.BiConsumer; /** Executor implementation which is backed by a Handler. */ public class HandlerExecutor implements ShellExecutor { + @NonNull private final Handler mHandler; + // See android.os.Process#THREAD_PRIORITY_* + private final int mDefaultThreadPriority; + private final int mBoostedThreadPriority; + // Number of current requests to boost thread priority + private int mBoostCount; + private final Object mBoostLock = new Object(); + // Default function for setting thread priority (tid, priority) + private BiConsumer<Integer, Integer> mSetThreadPriorityFn = + HandlerExecutor::setThreadPriorityInternal; public HandlerExecutor(@NonNull Handler handler) { + this(handler, THREAD_PRIORITY_DEFAULT, THREAD_PRIORITY_DEFAULT); + } + + /** + * Used only if this executor can be boosted, if so, it can be boosted to the given + * {@param boostPriority}. + */ + public HandlerExecutor(@NonNull Handler handler, int defaultThreadPriority, + int boostedThreadPriority) { mHandler = handler; + mDefaultThreadPriority = defaultThreadPriority; + mBoostedThreadPriority = boostedThreadPriority; + } + + @VisibleForTesting + void replaceSetThreadPriorityFn(BiConsumer<Integer, Integer> setThreadPriorityFn) { + mSetThreadPriorityFn = setThreadPriorityFn; } @Override @@ -56,9 +91,54 @@ public class HandlerExecutor implements ShellExecutor { } @Override + public void setBoost() { + synchronized (mBoostLock) { + if (mDefaultThreadPriority == mBoostedThreadPriority) { + // Nothing to boost + return; + } + if (mBoostCount == 0) { + mSetThreadPriorityFn.accept( + ((HandlerThread) mHandler.getLooper().getThread()).getThreadId(), + mBoostedThreadPriority); + } + mBoostCount++; + } + } + + @Override + public void resetBoost() { + synchronized (mBoostLock) { + mBoostCount--; + if (mBoostCount == 0) { + mSetThreadPriorityFn.accept( + ((HandlerThread) mHandler.getLooper().getThread()).getThreadId(), + mDefaultThreadPriority); + } + } + } + + @Override + public boolean isBoosted() { + synchronized (mBoostLock) { + return mBoostCount > 0; + } + } + + @Override + @NonNull + public Looper getLooper() { + return mHandler.getLooper(); + } + + @Override public void assertCurrentThread() { if (!mHandler.getLooper().isCurrentThread()) { throw new IllegalStateException("must be called on " + mHandler); } } + + private static void setThreadPriorityInternal(Integer tid, Integer priority) { + setThreadPriority(tid, priority); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java index 2c2961fd4b65..9e5071e8347b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java @@ -18,15 +18,15 @@ package com.android.wm.shell.common; import java.lang.reflect.Array; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** * Super basic Executor interface that adds support for delayed execution and removing callbacks. - * Intended to wrap Handler while better-supporting testing. + * Intended to wrap Handler while better-supporting testing. Not every ShellExecutor implementation + * may support boosting. */ -public interface ShellExecutor extends Executor { +public interface ShellExecutor extends BoostExecutor { /** * Executes the given runnable. If the caller is running on the same looper as this executor, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java index 813772f20a8a..2f5afcaa907b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java @@ -352,8 +352,8 @@ public class DividerSnapAlgorithm { ? mPinnedTaskbarInsets.right : mPinnedTaskbarInsets.bottom; float ratio = areOffscreenRatiosSupported() - ? SplitLayout.OFFSCREEN_ASYMMETRIC_RATIO - : SplitLayout.ONSCREEN_ONLY_ASYMMETRIC_RATIO; + ? SplitSpec.OFFSCREEN_ASYMMETRIC_RATIO + : SplitSpec.ONSCREEN_ONLY_ASYMMETRIC_RATIO; int size = (int) (ratio * (end - start)) - mDividerSize / 2; int leftTopPosition = start + pinnedTaskbarShiftStart + size; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 1852cda7e804..88c91db27bf3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -112,11 +112,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange private static final int FLING_EXIT_DURATION = 450; private static final int FLING_OFFSCREEN_DURATION = 500; - /** A split ratio used on larger screens, where we can fit both apps onscreen. */ - public static final float ONSCREEN_ONLY_ASYMMETRIC_RATIO = 0.33f; - /** A split ratio used on smaller screens, where we place one app mostly offscreen. */ - public static final float OFFSCREEN_ASYMMETRIC_RATIO = 0.1f; - // Here are some (arbitrarily decided) layer definitions used during animations to make sure the // layers stay in order. (During transitions, everything is reparented onto a transition root // and can be freely relayered.) @@ -236,7 +231,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange updateDividerConfig(mContext); mRootBounds.set(configuration.windowConfiguration.getBounds()); - mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); + updateLayouts(); mInteractionJankMonitor = InteractionJankMonitor.getInstance(); resetDividerPosition(); updateInvisibleRect(); @@ -490,7 +485,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mIsLargeScreen = configuration.smallestScreenWidthDp >= 600; mIsLeftRightSplit = SplitScreenUtils.isLeftRightSplit(mAllowLeftRightSplitInPortrait, configuration); - mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); + updateLayouts(); updateDividerConfig(mContext); initDividerPosition(mTempRect, wasLeftRightSplit); updateInvisibleRect(); @@ -518,7 +513,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange mRootBounds.set(tmpRect); mIsLeftRightSplit = SplitScreenUtils.isLeftRightSplit(mAllowLeftRightSplitInPortrait, mIsLargeScreen, mRootBounds.width() >= mRootBounds.height()); - mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); + updateLayouts(); initDividerPosition(mTempRect, wasLeftRightSplit); } @@ -652,7 +647,7 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange if (!mPinnedTaskbarInsets.equals(pinnedTaskbarInsets)) { mPinnedTaskbarInsets = pinnedTaskbarInsets; // Refresh the DividerSnapAlgorithm. - mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); + updateLayouts(); // If the divider is no longer placed on a snap point, animate it to the nearest one. DividerSnapAlgorithm.SnapTarget snapTarget = findSnapTarget(mDividerPosition, 0, false /* hardDismiss */); @@ -824,8 +819,22 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity, hardDismiss); } - private DividerSnapAlgorithm getSnapAlgorithm(Context context, Rect rootBounds) { - final Rect insets = getDisplayStableInsets(context); + /** + * (Re)calculates the split screen logic for this particular display/orientation. Refreshes the + * DividerSnapAlgorithm, which controls divider snap points, and populates a map in SplitState + * with bounds for all valid split layouts. + */ + private void updateLayouts() { + // Update SplitState map + + if (Flags.enableFlexibleTwoAppSplit()) { + mSplitState.populateLayouts( + mRootBounds, mDividerSize, mIsLeftRightSplit, mPinnedTaskbarInsets.toRect()); + } + + // Get new DividerSnapAlgorithm + + final Rect insets = getDisplayStableInsets(mContext); // Make split axis insets value same as the larger one to avoid bounds1 and bounds2 // have difference for avoiding size-compat mode when switching unresizable apps in @@ -835,10 +844,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange insets.set(insets.left, largerInsets, insets.right, largerInsets); } - return new DividerSnapAlgorithm( - context.getResources(), - rootBounds.width(), - rootBounds.height(), + mDividerSnapAlgorithm = new DividerSnapAlgorithm( + mContext.getResources(), + mRootBounds.width(), + mRootBounds.height(), mDividerSize, mIsLeftRightSplit, insets, @@ -1560,7 +1569,9 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final int imeTargetPosition = getImeTargetPosition(); mHasImeFocus = imeTargetPosition != SPLIT_POSITION_UNDEFINED; if (!mHasImeFocus) { - return 0; + if (!android.view.inputmethod.Flags.refactorInsetsController() || showing) { + return 0; + } } mStartImeTop = showing ? hiddenTop : shownTop; @@ -1613,7 +1624,11 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange @Override public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { - if (displayId != mDisplayId || !mHasImeFocus) return; + if (displayId != mDisplayId || !mHasImeFocus) { + if (!android.view.inputmethod.Flags.refactorInsetsController() || mImeShown) { + return; + } + } onProgress(getProgress(imeTop)); mSplitLayoutHandler.onLayoutPositionChanging(SplitLayout.this); } @@ -1621,7 +1636,12 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange @Override public void onImeEndPositioning(int displayId, boolean cancel, SurfaceControl.Transaction t) { - if (displayId != mDisplayId || !mHasImeFocus || cancel) return; + if (displayId != mDisplayId || cancel) return; + if (!mHasImeFocus) { + if (!android.view.inputmethod.Flags.refactorInsetsController() || mImeShown) { + return; + } + } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Split IME animation ending, canceled=%b", cancel); onProgress(1.0f); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitSpec.java new file mode 100644 index 000000000000..9c951bd89876 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitSpec.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common.split; + +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_10_90; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_33_66; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_66_33; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_90_10; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_10_45_45; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_33_33_33; +import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_3_45_45_10; +import static com.android.wm.shell.shared.split.SplitScreenConstants.stateToString; + +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.Log; + +import com.android.wm.shell.shared.split.SplitScreenConstants.SplitScreenState; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A reference class that stores the split layouts available in this device/orientation. Layouts are + * available as lists of RectFs, where each RectF represents the bounds of an app. + */ +public class SplitSpec { + private static final String TAG = "SplitSpec"; + private static final boolean DEBUG = true; + + /** A split ratio used on larger screens, where we can fit both apps onscreen. */ + public static final float ONSCREEN_ONLY_ASYMMETRIC_RATIO = 0.33f; + /** A split ratio used on smaller screens, where we place one app mostly offscreen. */ + public static final float OFFSCREEN_ASYMMETRIC_RATIO = 0.1f; + /** A 50-50 split ratio. */ + public static final float MIDDLE_RATIO = 0.5f; + + private final boolean mIsLeftRightSplit; + /** The usable display area, considering insets that affect split bounds. */ + private final RectF mUsableArea; + /** Half the divider size. */ + private final float mHalfDiv; + + /** A large map that stores all valid split layouts. */ + private final Map<Integer, List<RectF>> mLayouts = new HashMap<>(); + + /** Constructor; initializes the layout map. */ + public SplitSpec(Rect displayBounds, int dividerSize, boolean isLeftRightSplit, + Rect pinnedTaskbarInsets) { + mIsLeftRightSplit = isLeftRightSplit; + mUsableArea = new RectF(displayBounds); + mUsableArea.left += pinnedTaskbarInsets.left; + mUsableArea.top += pinnedTaskbarInsets.top; + mUsableArea.right -= pinnedTaskbarInsets.right; + mUsableArea.bottom -= pinnedTaskbarInsets.bottom; + mHalfDiv = dividerSize / 2f; + + // The "start" position, considering insets. + float s = isLeftRightSplit ? mUsableArea.left : mUsableArea.top; + // The "end" position, considering insets. + float e = isLeftRightSplit ? mUsableArea.right : mUsableArea.bottom; + // The "length" of the usable display (width or height). Apps are arranged along this axis. + float l = e - s; + float divPos; + float divPos2; + + // SNAP_TO_2_10_90 + divPos = s + (l * OFFSCREEN_ASYMMETRIC_RATIO); + createAppLayout(SNAP_TO_2_10_90, divPos); + + // SNAP_TO_2_33_66 + divPos = s + (l * ONSCREEN_ONLY_ASYMMETRIC_RATIO); + createAppLayout(SNAP_TO_2_33_66, divPos); + + // SNAP_TO_2_50_50 + divPos = s + (l * MIDDLE_RATIO); + createAppLayout(SNAP_TO_2_50_50, divPos); + + // SNAP_TO_2_66_33 + divPos = s + (l * (1 - ONSCREEN_ONLY_ASYMMETRIC_RATIO)); + createAppLayout(SNAP_TO_2_66_33, divPos); + + // SNAP_TO_2_90_10 + divPos = s + (l * (1 - OFFSCREEN_ASYMMETRIC_RATIO)); + createAppLayout(SNAP_TO_2_90_10, divPos); + + // SNAP_TO_3_10_45_45 + divPos = s + (l * OFFSCREEN_ASYMMETRIC_RATIO); + divPos2 = e - ((l * (1 - OFFSCREEN_ASYMMETRIC_RATIO)) / 2f); + createAppLayout(SNAP_TO_3_10_45_45, divPos, divPos2); + + // SNAP_TO_3_33_33_33 + divPos = s + (l * ONSCREEN_ONLY_ASYMMETRIC_RATIO); + divPos2 = e - (l * ONSCREEN_ONLY_ASYMMETRIC_RATIO); + createAppLayout(SNAP_TO_3_33_33_33, divPos, divPos2); + + // SNAP_TO_3_45_45_10 + divPos = s + ((l * (1 - OFFSCREEN_ASYMMETRIC_RATIO)) / 2f); + divPos2 = e - (l * OFFSCREEN_ASYMMETRIC_RATIO); + createAppLayout(SNAP_TO_3_45_45_10, divPos, divPos2); + + if (DEBUG) { + dump(); + } + } + + /** + * Creates a two-app layout and enters it into the layout map. + * @param divPos The position of the divider. + */ + private void createAppLayout(@SplitScreenState int state, float divPos) { + List<RectF> list = new ArrayList<>(); + RectF rect1 = new RectF(mUsableArea); + RectF rect2 = new RectF(mUsableArea); + if (mIsLeftRightSplit) { + rect1.right = divPos - mHalfDiv; + rect2.left = divPos + mHalfDiv; + } else { + rect1.top = divPos - mHalfDiv; + rect2.bottom = divPos + mHalfDiv; + } + list.add(rect1); + list.add(rect2); + mLayouts.put(state, list); + } + + /** + * Creates a three-app layout and enters it into the layout map. + * @param divPos1 The position of the first divider. + * @param divPos2 The position of the second divider. + */ + private void createAppLayout(@SplitScreenState int state, float divPos1, float divPos2) { + List<RectF> list = new ArrayList<>(); + RectF rect1 = new RectF(mUsableArea); + RectF rect2 = new RectF(mUsableArea); + RectF rect3 = new RectF(mUsableArea); + if (mIsLeftRightSplit) { + rect1.right = divPos1 - mHalfDiv; + rect2.left = divPos1 + mHalfDiv; + rect2.right = divPos2 - mHalfDiv; + rect3.left = divPos2 + mHalfDiv; + } else { + rect1.right = divPos1 - mHalfDiv; + rect2.left = divPos1 + mHalfDiv; + rect3.right = divPos2 - mHalfDiv; + rect3.left = divPos2 + mHalfDiv; + } + list.add(rect1); + list.add(rect2); + list.add(rect3); + mLayouts.put(state, list); + } + + /** Logs all calculated layouts */ + private void dump() { + mLayouts.forEach((k, v) -> { + Log.d(TAG, stateToString(k)); + v.forEach(rect -> Log.d(TAG, " - " + rect.toShortString())); + }); + } + + /** Returns the layout associated with a given split state. */ + List<RectF> getSpec(@SplitScreenState int state) { + return mLayouts.get(state); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java index 71758e0d2159..d1d133d16ae4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitState.java @@ -19,11 +19,17 @@ package com.android.wm.shell.common.split; import static com.android.wm.shell.shared.split.SplitScreenConstants.NOT_IN_SPLIT; import static com.android.wm.shell.shared.split.SplitScreenConstants.SplitScreenState; +import android.graphics.Rect; +import android.graphics.RectF; + +import java.util.List; + /** * A class that manages the "state" of split screen. See {@link SplitScreenState} for definitions. */ public class SplitState { private @SplitScreenState int mState = NOT_IN_SPLIT; + private SplitSpec mSplitSpec; /** Updates the current state of split screen on this device. */ public void set(@SplitScreenState int newState) { @@ -39,4 +45,16 @@ public class SplitState { public void exit() { set(NOT_IN_SPLIT); } + + /** Refresh the valid layouts for this display/orientation. */ + public void populateLayouts(Rect displayBounds, int dividerSize, boolean isLeftRightSplit, + Rect pinnedTaskbarInsets) { + mSplitSpec = + new SplitSpec(displayBounds, dividerSize, isLeftRightSplit, pinnedTaskbarInsets); + } + + /** Returns the layout associated with a given split state. */ + public List<RectF> getLayout(@SplitScreenState int state) { + return mSplitSpec.getSpec(state); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 9d4b4bbb33de..fe6066c8c4fb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -55,6 +55,7 @@ import com.android.wm.shell.compatui.api.CompatUIHandler; import com.android.wm.shell.compatui.api.CompatUIInfo; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonClicked; import com.android.wm.shell.desktopmode.DesktopUserRepositories; +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -70,7 +71,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** @@ -667,9 +667,10 @@ public class CompatUIController implements OnDisplaysChangedListener, private void createOrUpdateUserAspectRatioSettingsLayout(@NonNull TaskInfo taskInfo, @Nullable ShellTaskOrganizer.TaskListener taskListener) { + boolean overridesShowAppHandle = DesktopModeStatus.overridesShowAppHandle(mContext); if (mUserAspectRatioSettingsLayout != null) { if (mUserAspectRatioSettingsLayout.needsToBeRecreated(taskInfo, taskListener) - || mIsInDesktopMode) { + || mIsInDesktopMode || overridesShowAppHandle) { mUserAspectRatioSettingsLayout.release(); mUserAspectRatioSettingsLayout = null; } else { @@ -682,8 +683,9 @@ public class CompatUIController implements OnDisplaysChangedListener, return; } } - if (mIsInDesktopMode) { - // Return if in desktop mode. + if (mIsInDesktopMode || overridesShowAppHandle) { + // Return if in desktop mode or app handle menu is already showing change aspect ratio + // option. return; } // Create a new UI layout. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt index 819b11095a9b..2d0a3f54f85f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt @@ -67,8 +67,8 @@ class LetterboxCommandHandler @Inject constructor( return false } return when (args.size) { - 1 -> onShellDisplayCommand(args[0], pw) - 2 -> onShellUpdateCommand(args[0], args[1], pw) + 1 -> onNoParamsCommand(args[0], pw) + 2 -> onSingleParamCommand(args[0], args[1], pw) else -> { pw.println("Invalid command: " + args[0]) return false @@ -89,11 +89,17 @@ class LetterboxCommandHandler @Inject constructor( $prefix name, for example, @android:color/system_accent2_50. $prefix backgroundColorReset" $prefix Resets the background color to the default value." + $prefix cornerRadius" + $prefix Corners radius (in pixels) for activities in the letterbox mode." + $prefix If cornerRadius < 0, it will be ignored and corners of the" + $prefix activity won't be rounded." + $prefix cornerRadiusReset" + $prefix Resets the rounded corners radius to the default value." """.trimIndent() ) } - private fun onShellUpdateCommand(command: String, value: String, pw: PrintWriter): Boolean { + private fun onSingleParamCommand(command: String, value: String, pw: PrintWriter): Boolean { when (command) { "backgroundColor" -> { return invokeWhenValid( @@ -120,10 +126,17 @@ class LetterboxCommandHandler @Inject constructor( } ) - "backgroundColorReset" -> { - letterboxConfiguration.resetLetterboxBackgroundColor() - return true - } + "cornerRadius" -> return invokeWhenValid( + pw, + value, + ::strToInt{ it >= 0 }, + { radius -> + letterboxConfiguration.setLetterboxActivityCornersRadius(radius) + }, + { r -> + "$r is not a valid radius. It must be an integer >= 0." + } + ) else -> { pw.println("Invalid command: $value") @@ -132,7 +145,7 @@ class LetterboxCommandHandler @Inject constructor( } } - private fun onShellDisplayCommand(command: String, pw: PrintWriter): Boolean { + private fun onNoParamsCommand(command: String, pw: PrintWriter): Boolean { when (command) { "backgroundColor" -> { pw.println( @@ -144,6 +157,24 @@ class LetterboxCommandHandler @Inject constructor( return true } + "backgroundColorReset" -> { + letterboxConfiguration.resetLetterboxBackgroundColor() + return true + } + + "cornerRadius" -> { + pw.println( + " Rounded corners radius: " + + "${letterboxConfiguration.getLetterboxActivityCornersRadius()} px." + ) + return true + } + + "cornerRadiusReset" -> { + letterboxConfiguration.resetLetterboxActivityCornersRadius() + return true + } + else -> { pw.println("Invalid command: $command") return false @@ -181,4 +212,15 @@ class LetterboxCommandHandler @Inject constructor( } catch (e: IllegalArgumentException) { null } + + // Converts a String to Int which if possible or it returns null otherwise. + // If a predicate is set, it also returns [null] if the predicate evaluate to [false]. + private fun strToInt(predicate: (Int) -> Boolean = { _ -> true }): (String) -> Int? = { str -> + try { + val value = str.toInt() + if (predicate(value)) value else null + } catch (e: IllegalArgumentException) { + null + } + } } 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/WMShellConcurrencyModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java index c5644a8f6876..d7ddbdeaa6da 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java @@ -18,6 +18,7 @@ package com.android.wm.shell.dagger; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.THREAD_PRIORITY_DISPLAY; +import static android.os.Process.THREAD_PRIORITY_FOREGROUND; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import android.content.Context; @@ -205,13 +206,14 @@ public abstract class WMShellConcurrencyModule { } /** - * Provides a Shell background thread Executor for low priority background tasks. + * Provides a Shell background thread Executor for low priority background tasks. The thread + * may also be boosted to THREAD_PRIORITY_FOREGROUND if necessary. */ @WMSingleton @Provides @ShellBackgroundThread public static ShellExecutor provideSharedBackgroundExecutor( @ShellBackgroundThread Handler handler) { - return new HandlerExecutor(handler); + return new HandlerExecutor(handler, THREAD_PRIORITY_BACKGROUND, THREAD_PRIORITY_FOREGROUND); } } 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..9d2da41725b1 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); } @@ -1016,12 +1025,14 @@ public abstract class WMShellModule { static DesktopUserRepositories provideDesktopUserRepositories( Context context, ShellInit shellInit, + ShellController shellController, DesktopPersistentRepository desktopPersistentRepository, DesktopRepositoryInitializer desktopRepositoryInitializer, @ShellMainThread CoroutineScope mainScope, UserManager userManager ) { - return new DesktopUserRepositories(context, shellInit, desktopPersistentRepository, + return new DesktopUserRepositories(context, shellInit, shellController, + desktopPersistentRepository, desktopRepositoryInitializer, mainScope, userManager); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt index 8e2a412764eb..536dc2a58534 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt @@ -74,13 +74,11 @@ class DesktopImmersiveController( { SurfaceControl.Transaction() }, ) - @VisibleForTesting var state: TransitionState? = null - - @VisibleForTesting val pendingExternalExitTransitions = mutableListOf<ExternalPendingExit>() + @VisibleForTesting val pendingImmersiveTransitions = mutableListOf<PendingTransition>() /** Whether there is an immersive transition that hasn't completed yet. */ private val inProgress: Boolean - get() = state != null || pendingExternalExitTransitions.isNotEmpty() + get() = pendingImmersiveTransitions.isNotEmpty() private val rectEvaluator = RectEvaluator() @@ -101,20 +99,19 @@ class DesktopImmersiveController( if (inProgress) { logV( "Cannot start entry because transition(s) already in progress: %s", - getRunningTransitions(), + pendingImmersiveTransitions, ) return } val wct = WindowContainerTransaction().apply { setBounds(taskInfo.token, Rect()) } logV("Moving task ${taskInfo.taskId} into immersive mode") val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this) - state = - TransitionState( - transition = transition, - displayId = taskInfo.displayId, - taskId = taskInfo.taskId, - direction = Direction.ENTER, - ) + addPendingImmersiveTransition( + taskId = taskInfo.taskId, + displayId = taskInfo.displayId, + direction = Direction.ENTER, + transition = transition, + ) } /** Starts a transition to move an immersive task out of immersive. */ @@ -123,7 +120,7 @@ class DesktopImmersiveController( if (inProgress) { logV( "Cannot start exit because transition(s) already in progress: %s", - getRunningTransitions(), + pendingImmersiveTransitions, ) return } @@ -134,13 +131,12 @@ class DesktopImmersiveController( } logV("Moving task %d out of immersive mode, reason: %s", taskInfo.taskId, reason) val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this) - state = - TransitionState( - transition = transition, - displayId = taskInfo.displayId, - taskId = taskInfo.taskId, - direction = Direction.EXIT, - ) + addPendingImmersiveTransition( + taskId = taskInfo.taskId, + displayId = taskInfo.displayId, + direction = Direction.EXIT, + transition = transition, + ) } /** @@ -194,7 +190,13 @@ class DesktopImmersiveController( return ExitResult.Exit( exitingTask = immersiveTask, runOnTransitionStart = { transition -> - addPendingImmersiveExit(immersiveTask, displayId, transition) + addPendingImmersiveTransition( + taskId = immersiveTask, + displayId = displayId, + direction = Direction.EXIT, + transition = transition, + animate = false, + ) }, ) } @@ -220,10 +222,12 @@ class DesktopImmersiveController( return ExitResult.Exit( exitingTask = taskInfo.taskId, runOnTransitionStart = { transition -> - addPendingImmersiveExit( + addPendingImmersiveTransition( taskId = taskInfo.taskId, displayId = taskInfo.displayId, + direction = Direction.EXIT, transition = transition, + animate = false, ) }, ) @@ -233,14 +237,26 @@ class DesktopImmersiveController( /** Whether the [change] in the [transition] is a known immersive change. */ fun isImmersiveChange(transition: IBinder, change: TransitionInfo.Change): Boolean { - return pendingExternalExitTransitions.any { + return pendingImmersiveTransitions.any { it.transition == transition && it.taskId == change.taskInfo?.taskId } } - private fun addPendingImmersiveExit(taskId: Int, displayId: Int, transition: IBinder) { - pendingExternalExitTransitions.add( - ExternalPendingExit(taskId = taskId, displayId = displayId, transition = transition) + private fun addPendingImmersiveTransition( + taskId: Int, + displayId: Int, + direction: Direction, + transition: IBinder, + animate: Boolean = true, + ) { + pendingImmersiveTransitions.add( + PendingTransition( + taskId = taskId, + displayId = displayId, + direction = direction, + transition = transition, + animate = animate, + ) ) } @@ -251,19 +267,17 @@ class DesktopImmersiveController( finishTransaction: SurfaceControl.Transaction, finishCallback: Transitions.TransitionFinishCallback, ): Boolean { - val state = requireState() - check(state.transition == transition) { - "Transition $transition did not match expected state=$state" - } + val immersiveTransition = getImmersiveTransition(transition) ?: return false + if (!immersiveTransition.animate) return false logD("startAnimation transition=%s", transition) animateResize( - targetTaskId = state.taskId, + targetTaskId = immersiveTransition.taskId, info = info, startTransaction = startTransaction, finishTransaction = finishTransaction, finishCallback = { finishCallback.onTransitionFinished(/* wct= */ null) - clearState() + pendingImmersiveTransitions.remove(immersiveTransition) }, ) return true @@ -346,18 +360,6 @@ class DesktopImmersiveController( request: TransitionRequestInfo, ): WindowContainerTransaction? = null - override fun onTransitionConsumed( - transition: IBinder, - aborted: Boolean, - finishTransaction: SurfaceControl.Transaction?, - ) { - val state = this.state ?: return - if (transition == state.transition && aborted) { - clearState() - } - super.onTransitionConsumed(transition, aborted, finishTransaction) - } - /** * Called when any transition in the system is ready to play. This is needed to update the * repository state before window decorations are drawn (which happens immediately after @@ -371,67 +373,42 @@ class DesktopImmersiveController( finishTransaction: SurfaceControl.Transaction, ) { val desktopRepository: DesktopRepository = desktopUserRepositories.current - // Check if this is a pending external exit transition. - val pendingExit = - pendingExternalExitTransitions.firstOrNull { pendingExit -> - pendingExit.transition == transition - } - if (pendingExit != null) { - if (info.hasTaskChange(taskId = pendingExit.taskId)) { - if (desktopRepository.isTaskInFullImmersiveState(pendingExit.taskId)) { - logV("Pending external exit for task#%d verified", pendingExit.taskId) - desktopRepository.setTaskInFullImmersiveState( - displayId = pendingExit.displayId, - taskId = pendingExit.taskId, - immersive = false, - ) - if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) { - desktopRepository.removeBoundsBeforeFullImmersive(pendingExit.taskId) - } - } - } - return - } + val pendingTransition = getImmersiveTransition(transition) - // Check if this is a direct immersive enter/exit transition. - if (transition == state?.transition) { - val state = requireState() - val immersiveChange = - info.changes.firstOrNull { c -> c.taskInfo?.taskId == state.taskId } + if (pendingTransition != null) { + val taskId = pendingTransition.taskId + val immersiveChange = info.getTaskChange(taskId = taskId) if (immersiveChange == null) { logV( - "Direct move for task#%d in %s direction missing immersive change.", - state.taskId, - state.direction, + "Transition for task#%d in %s direction missing immersive change.", + taskId, + pendingTransition.direction, ) return } - val startBounds = immersiveChange.startAbsBounds - logV("Direct move for task#%d in %s direction verified", state.taskId, state.direction) - - when (state.direction) { - Direction.ENTER -> { - desktopRepository.setTaskInFullImmersiveState( - displayId = state.displayId, - taskId = state.taskId, - immersive = true, - ) - if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) { - desktopRepository.saveBoundsBeforeFullImmersive(state.taskId, startBounds) + logV( + "Immersive transition for task#%d in %s direction verified", + taskId, + pendingTransition.direction, + ) + desktopRepository.setTaskInFullImmersiveState( + displayId = pendingTransition.displayId, + taskId = taskId, + immersive = pendingTransition.direction == Direction.ENTER, + ) + if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) { + when (pendingTransition.direction) { + Direction.EXIT -> { + desktopRepository.removeBoundsBeforeFullImmersive(taskId) } - } - Direction.EXIT -> { - desktopRepository.setTaskInFullImmersiveState( - displayId = state.displayId, - taskId = state.taskId, - immersive = false, - ) - if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) { - desktopRepository.removeBoundsBeforeFullImmersive(state.taskId) + Direction.ENTER -> { + desktopRepository.saveBoundsBeforeFullImmersive( + taskId, + immersiveChange.startAbsBounds, + ) } } } - return } // Check if this is an untracked exit transition, like display rotation. @@ -450,35 +427,31 @@ class DesktopImmersiveController( } override fun onTransitionMerged(merged: IBinder, playing: IBinder) { - val pendingExit = - pendingExternalExitTransitions.firstOrNull { pendingExit -> - pendingExit.transition == merged + val pendingTransition = + pendingImmersiveTransitions.firstOrNull { pendingTransition -> + pendingTransition.transition == merged } - if (pendingExit != null) { + if (pendingTransition != null) { logV( - "Pending exit transition %s for task#%s merged into %s", + "Pending transition %s for task#%s merged into %s", merged, - pendingExit.taskId, + pendingTransition.taskId, playing, ) - pendingExit.transition = playing + pendingTransition.transition = playing } } override fun onTransitionFinished(transition: IBinder, aborted: Boolean) { - val pendingExit = - pendingExternalExitTransitions.firstOrNull { pendingExit -> - pendingExit.transition == transition - } - if (pendingExit != null) { - logV("Pending exit transition %s for task#%s finished", transition, pendingExit) - pendingExternalExitTransitions.remove(pendingExit) + val pendingTransition = getImmersiveTransition(transition) + if (pendingTransition != null) { + logV("Pending exit transition %s for task#%s finished", transition, pendingTransition) + pendingImmersiveTransitions.remove(pendingTransition) } } - private fun clearState() { - state = null - } + private fun getImmersiveTransition(transition: IBinder) = + pendingImmersiveTransitions.firstOrNull { it.transition == transition } private fun getExitDestinationBounds(taskInfo: RunningTaskInfo): Rect { val displayLayout = @@ -496,24 +469,13 @@ class DesktopImmersiveController( } } - private fun requireState(): TransitionState = - state ?: error("Expected non-null transition state") - - private fun getRunningTransitions(): List<IBinder> { - val running = mutableListOf<IBinder>() - state?.let { running.add(it.transition) } - pendingExternalExitTransitions.forEach { running.add(it.transition) } - return running - } - - private fun TransitionInfo.hasTaskChange(taskId: Int): Boolean = - changes.any { c -> c.taskInfo?.taskId == taskId } + private fun TransitionInfo.getTaskChange(taskId: Int): TransitionInfo.Change? = + changes.firstOrNull { c -> c.taskInfo?.taskId == taskId } private fun dump(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " pw.println("${prefix}DesktopImmersiveController") - pw.println(innerPrefix + "state=" + state) - pw.println(innerPrefix + "pendingExternalExitTransitions=" + pendingExternalExitTransitions) + pw.println(innerPrefix + "pendingImmersiveTransitions=" + pendingImmersiveTransitions) } /** The state of the currently running transition. */ @@ -526,12 +488,22 @@ class DesktopImmersiveController( ) /** - * Tracks state of a transition involving an immersive exit that is external to this class' own - * transitions. This usually means transitions that exit immersive mode as a side-effect and not - * the primary action (for example, minimizing the immersive task or launching a new task on top - * of the immersive task). + * Tracks state of a transition involving an immersive enter or exit. This includes both + * transitions that should and should not be animated by this handler. + * + * @param taskId of the task that should enter/exit immersive mode + * @param displayId of the display that should enter/exit immersive mode + * @param direction of the immersive transition + * @param transition that will apply this transaction + * @param animate whether transition should be animated by this handler */ - data class ExternalPendingExit(val taskId: Int, val displayId: Int, var transition: IBinder) + data class PendingTransition( + val taskId: Int, + val displayId: Int, + val direction: Direction, + var transition: IBinder, + val animate: Boolean, + ) /** The result of an external exit request. */ sealed class ExitResult { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt index 7764688695f7..50187d552b09 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt @@ -77,6 +77,10 @@ class DesktopMixedTransitionHandler( override fun startMinimizedModeTransition(wct: WindowContainerTransaction?): IBinder = freeformTaskTransitionHandler.startMinimizedModeTransition(wct) + /** Delegates starting PiP transition to [FreeformTaskTransitionHandler]. */ + override fun startPipTransition(wct: WindowContainerTransaction?): IBinder = + freeformTaskTransitionHandler.startPipTransition(wct) + /** Starts close transition and handles or delegates desktop task close animation. */ override fun startRemoveTransition(wct: WindowContainerTransaction?): IBinder { if ( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index 14623cf9e703..606a729305b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -235,8 +235,7 @@ fun isTaskWidthOrHeightEqual(taskBounds: Rect, stableBounds: Rect): Boolean { /** Returns true if task bound is equal to stable bounds else returns false. */ fun isTaskBoundsEqual(taskBounds: Rect, stableBounds: Rect): Boolean { - return taskBounds.width() == stableBounds.width() && - taskBounds.height() == stableBounds.height() + return taskBounds == stableBounds } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index 80d8ecc127fe..cd37113666bb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -53,6 +53,7 @@ import android.view.animation.DecelerateInterpolator; import androidx.annotation.VisibleForTesting; import com.android.internal.policy.SystemBarUtils; +import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.DisplayController; @@ -245,9 +246,17 @@ public class DesktopModeVisualIndicator { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final Resources resources = mContext.getResources(); final DisplayMetrics metrics = resources.getDisplayMetrics(); - final int screenWidth = metrics.widthPixels; - final int screenHeight = metrics.heightPixels; - + final int screenWidth; + final int screenHeight; + if (Flags.enableBugFixesForSecondaryDisplay()) { + final DisplayLayout displayLayout = + mDisplayController.getDisplayLayout(mTaskInfo.displayId); + screenWidth = displayLayout.width(); + screenHeight = displayLayout.height(); + } else { + screenWidth = metrics.widthPixels; + screenHeight = metrics.heightPixels; + } mView = new View(mContext); final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); 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 d5a2a4083b1d..9a1abd52846b 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 @@ -50,6 +50,7 @@ import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_NONE import android.view.WindowManager.TRANSIT_OPEN +import android.view.WindowManager.TRANSIT_PIP import android.view.WindowManager.TRANSIT_TO_FRONT import android.widget.Toast import android.window.DesktopModeFlags @@ -220,6 +221,7 @@ class DesktopTasksController( // Launch cookie used to identify a drag and drop transition to fullscreen after it has begun. // Used to prevent handleRequest from moving the new fullscreen task to freeform. private var dragAndDropFullscreenCookie: Binder? = null + private var pendingPipTransitionAndTask: Pair<IBinder, Int>? = null init { desktopMode = DesktopModeImpl() @@ -361,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 @@ -374,12 +383,13 @@ class DesktopTasksController( taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction(), transitionSource: DesktopModeTransitionSource, + remoteTransition: RemoteTransition? = null, ): Boolean { val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId) if (runningTask == null) { - return moveBackgroundTaskToDesktop(taskId, wct, transitionSource) + return moveBackgroundTaskToDesktop(taskId, wct, transitionSource, remoteTransition) } - moveRunningTaskToDesktop(runningTask, wct, transitionSource) + moveRunningTaskToDesktop(runningTask, wct, transitionSource, remoteTransition) return true } @@ -387,6 +397,7 @@ class DesktopTasksController( taskId: Int, wct: WindowContainerTransaction, transitionSource: DesktopModeTransitionSource, + remoteTransition: RemoteTransition? = null, ): Boolean { if (recentTasksController?.findTaskInBackground(taskId) == null) { logW("moveBackgroundTaskToDesktop taskId=%d not found", taskId) @@ -409,8 +420,17 @@ class DesktopTasksController( .apply { launchWindowingMode = WINDOWING_MODE_FREEFORM } .toBundle(), ) - // TODO(343149901): Add DPI changes for task launch - val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + + val transition: IBinder + if (remoteTransition != null) { + val transitionType = transitionType(remoteTransition) + val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition) + transition = transitions.startTransition(transitionType, wct, remoteTransitionHandler) + remoteTransitionHandler.setTransition(transition) + } else { + // TODO(343149901): Add DPI changes for task launch + transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + } desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( FREEFORM_ANIMATION_DURATION ) @@ -424,6 +444,7 @@ class DesktopTasksController( task: RunningTaskInfo, wct: WindowContainerTransaction = WindowContainerTransaction(), transitionSource: DesktopModeTransitionSource, + remoteTransition: RemoteTransition? = null, ) { if ( DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue() && @@ -441,12 +462,21 @@ class DesktopTasksController( excludeTaskId = task.taskId, reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH, ) + // Bring other apps to front first val taskIdToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) addMoveToDesktopChanges(wct, task) - val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + val transition: IBinder + if (remoteTransition != null) { + val transitionType = transitionType(remoteTransition) + val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition) + transition = transitions.startTransition(transitionType, wct, remoteTransitionHandler) + remoteTransitionHandler.setTransition(transition) + } else { + transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource) + } desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( FREEFORM_ANIMATION_DURATION ) @@ -557,6 +587,26 @@ class DesktopTasksController( } fun minimizeTask(taskInfo: RunningTaskInfo) { + val wct = WindowContainerTransaction() + + val isMinimizingToPip = taskInfo.pictureInPictureParams?.isAutoEnterEnabled() ?: false + // If task is going to PiP, start a PiP transition instead of a minimize transition + if (isMinimizingToPip) { + val requestInfo = TransitionRequestInfo( + TRANSIT_PIP, /* triggerTask= */ null, taskInfo, /* remoteTransition= */ null, + /* displayChange= */ null, /* flags= */ 0 + ) + val requestRes = transitions.dispatchRequest(Binder(), requestInfo, /* skip= */ null) + wct.merge(requestRes.second, true) + pendingPipTransitionAndTask = + freeformTaskTransitionStarter.startPipTransition(wct) to taskInfo.taskId + return + } + + minimizeTaskInner(taskInfo) + } + + private fun minimizeTaskInner(taskInfo: RunningTaskInfo) { val taskId = taskInfo.taskId val displayId = taskInfo.displayId val wct = WindowContainerTransaction() @@ -884,7 +934,10 @@ class DesktopTasksController( destinationBounds.height(), displayController, ) - toggleResizeDesktopTaskTransitionHandler.startTransition(wct) + toggleResizeDesktopTaskTransitionHandler.startTransition( + wct, + interaction.animationStartBounds, + ) } private fun dragToMaximizeDesktopTask( @@ -915,6 +968,7 @@ class DesktopTasksController( direction = ToggleTaskSizeInteraction.Direction.MAXIMIZE, source = ToggleTaskSizeInteraction.Source.HEADER_DRAG_TO_TOP, inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent), + animationStartBounds = currentDragBounds, ), ) } @@ -1202,9 +1256,12 @@ class DesktopTasksController( moveHomeTask(wct, toTop = true) // Currently, we only handle the desktop on the default display really. - if (displayId == DEFAULT_DISPLAY && ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) { + if ( + (displayId == DEFAULT_DISPLAY || Flags.enableBugFixesForSecondaryDisplay()) && + ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() + ) { // Add translucent wallpaper activity to show the wallpaper underneath - addWallpaperActivity(wct) + addWallpaperActivity(displayId, wct) } val expandedTasksOrderedFrontToBack = taskRepository.getExpandedTasksOrdered(displayId) @@ -1253,7 +1310,7 @@ class DesktopTasksController( ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ toTop) } } - private fun addWallpaperActivity(wct: WindowContainerTransaction) { + private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { logV("addWallpaperActivity") val userHandle = UserHandle.of(userId) val userContext = context.createContextAsUser(userHandle, /* flags= */ 0) @@ -1264,6 +1321,9 @@ class DesktopTasksController( launchWindowingMode = WINDOWING_MODE_FULLSCREEN pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS + if (Flags.enableBugFixesForSecondaryDisplay()) { + launchDisplayId = displayId + } } val pendingIntent = PendingIntent.getActivityAsUser( @@ -1329,6 +1389,21 @@ class DesktopTasksController( return false } + override fun onTransitionConsumed( + transition: IBinder, + aborted: Boolean, + finishT: Transaction? + ) { + pendingPipTransitionAndTask?.let { (pipTransition, taskId) -> + if (transition == pipTransition) { + if (aborted) { + shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { minimizeTaskInner(it) } + } + pendingPipTransitionAndTask = null + } + } + } + override fun handleRequest( transition: IBinder, request: TransitionRequestInfo, @@ -2048,7 +2123,11 @@ class DesktopTasksController( syncQueue, taskInfo, displayController, - context, + if (Flags.enableBugFixesForSecondaryDisplay()) { + displayController.getDisplayContext(taskInfo.displayId) + } else { + context + }, taskSurface, rootTaskDisplayAreaOrganizer, dragStartState, @@ -2599,9 +2678,17 @@ class DesktopTasksController( } } - override fun moveToDesktop(taskId: Int, transitionSource: DesktopModeTransitionSource) { + override fun moveToDesktop( + taskId: Int, + transitionSource: DesktopModeTransitionSource, + remoteTransition: RemoteTransition?, + ) { executeRemoteCallWithTaskPermission(controller, "moveTaskToDesktop") { c -> - c.moveTaskToDesktop(taskId, transitionSource = transitionSource) + c.moveTaskToDesktop( + taskId, + transitionSource = transitionSource, + remoteTransition = remoteTransition, + ) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt index e5f52839d9f4..8b5d1c502bc9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt @@ -28,6 +28,7 @@ import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.UserChangeListener import kotlinx.coroutines.CoroutineScope @@ -36,6 +37,7 @@ import kotlinx.coroutines.CoroutineScope class DesktopUserRepositories( context: Context, shellInit: ShellInit, + private val shellController: ShellController, private val persistentRepository: DesktopPersistentRepository, private val repositoryInitializer: DesktopRepositoryInitializer, @ShellMainThread private val mainCoroutineScope: CoroutineScope, @@ -61,15 +63,16 @@ class DesktopUserRepositories( init { userId = ActivityManager.getCurrentUser() if (DesktopModeStatus.canEnterDesktopMode(context)) { - shellInit.addInitCallback(::initRepoFromPersistentStorage, this) + shellInit.addInitCallback(::onInit, this) } if (Flags.enableDesktopWindowingHsum()) { userIdToProfileIdsMap[userId] = userManager.getProfiles(userId).map { it.id } } } - private fun initRepoFromPersistentStorage() { + private fun onInit() { repositoryInitializer.initialize(this) + shellController.addUserChangeListener(this) } /** Returns [DesktopRepository] for the parent user id. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl index aac2361f717e..fa383cb55118 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl @@ -53,7 +53,8 @@ interface IDesktopMode { oneway void setTaskListener(IDesktopTaskListener listener); /** Move a task with given `taskId` to desktop */ - void moveToDesktop(int taskId, in DesktopModeTransitionSource transitionSource); + void moveToDesktop(int taskId, in DesktopModeTransitionSource transitionSource, + in @nullable RemoteTransition remoteTransition); /** Remove desktop on the given display */ oneway void removeDesktop(int displayId); 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/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt index c5fca028a1a6..45d1281ba0e0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt @@ -23,7 +23,6 @@ import android.content.res.Resources import android.graphics.Point import android.os.SystemProperties import android.util.Slog -import androidx.core.content.withStyledAttributes import com.android.window.flags.Flags import com.android.wm.shell.R import com.android.wm.shell.desktopmode.CaptionState @@ -299,31 +298,12 @@ class AppHandleEducationController( } private fun tooltipColorScheme(captionState: CaptionState): TooltipColorScheme { - context.withStyledAttributes( - set = null, - attrs = - intArrayOf( - com.android.internal.R.attr.materialColorOnTertiaryFixed, - com.android.internal.R.attr.materialColorTertiaryFixed, - com.android.internal.R.attr.materialColorTertiaryFixedDim, - ), - defStyleAttr = 0, - defStyleRes = 0, - ) { - val onTertiaryFixed = getColor(/* index= */ 0, /* defValue= */ 0) - val tertiaryFixed = getColor(/* index= */ 1, /* defValue= */ 0) - val tertiaryFixedDim = getColor(/* index= */ 2, /* defValue= */ 0) - val taskInfo = (captionState as CaptionState.AppHandle).runningTaskInfo + val onTertiaryFixed = + context.getColor(com.android.internal.R.color.materialColorOnTertiaryFixed) + val tertiaryFixed = + context.getColor(com.android.internal.R.color.materialColorTertiaryFixed) - val tooltipContainerColor = - if (decorThemeUtil.getAppTheme(taskInfo) == Theme.LIGHT) { - tertiaryFixed - } else { - tertiaryFixedDim - } - return TooltipColorScheme(tooltipContainerColor, onTertiaryFixed, onTertiaryFixed) - } - return TooltipColorScheme(0, 0, 0) + return TooltipColorScheme(tertiaryFixed, onTertiaryFixed, onTertiaryFixed) } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md index 9d015357b60b..837a6dd32ff2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/threading.md @@ -36,7 +36,8 @@ the product. thread) - This is always another thread even if config_enableShellMainThread is not set true - **Note**: - - This thread runs with `THREAD_PRIORITY_BACKGROUND` priority + - This thread runs with `THREAD_PRIORITY_BACKGROUND` priority but can be requested to be boosted + to `THREAD_PRIORITY_FOREGROUND` - `ShellAnimationThread` (currently only used for Transitions and Splitscreen, but potentially all animations could be offloaded here) - `ShellSplashScreenThread` (only for use with splashscreens) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index 2ae9828ca0db..52b6c62b0721 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -18,6 +18,7 @@ package com.android.wm.shell.freeform; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.WindowManager.TRANSIT_PIP; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -99,6 +100,12 @@ public class FreeformTaskTransitionHandler return token; } + @Override + public IBinder startPipTransition(WindowContainerTransaction wct) { + final IBinder token = mTransitions.startTransition(TRANSIT_PIP, wct, null); + mPendingTransitionTokens.add(token); + return token; + } @Override public IBinder startRemoveTransition(WindowContainerTransaction wct) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java index 5984d486f838..a874a5be426d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java @@ -51,4 +51,13 @@ public interface FreeformTaskTransitionStarter { * @return the started transition */ IBinder startRemoveTransition(WindowContainerTransaction wct); + + /** + * Starts PiP transition + * + * @param wct the {@link WindowContainerTransaction} that launches the PiP + * + * @return the started transition + */ + IBinder startPipTransition(WindowContainerTransaction wct); }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 1efe2ffd804a..acb5622b041c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -55,6 +55,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; import com.android.internal.util.Preconditions; +import com.android.window.flags.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; @@ -123,7 +124,6 @@ public class PipTransition extends PipTransitionController implements // Internal state and relevant cached info // - @Nullable private Transitions.TransitionFinishCallback mFinishCallback; private ValueAnimator mTransitionAnimator; @@ -235,7 +235,6 @@ public class PipTransition extends PipTransitionController implements @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { - mFinishCallback = finishCallback; if (transition == mEnterTransition || info.getType() == TRANSIT_PIP) { mEnterTransition = null; // If we are in swipe PiP to Home transition we are ENTERING_PIP as a jumpcut transition @@ -281,7 +280,6 @@ public class PipTransition extends PipTransitionController implements if (isRemovePipTransition(info)) { return removePipImmediately(info, startTransaction, finishTransaction, finishCallback); } - mFinishCallback = null; return false; } @@ -330,6 +328,7 @@ public class PipTransition extends PipTransitionController implements if (pipChange == null) { return false; } + mFinishCallback = finishCallback; // We expect the PiP activity as a separate change in a config-at-end transition; // only flings are not using config-at-end for resize bounds changes TransitionInfo.Change pipActivityChange = getDeferConfigActivityChange(info, @@ -377,6 +376,7 @@ public class PipTransition extends PipTransitionController implements if (pipActivityChange == null) { return false; } + mFinishCallback = finishCallback; final SurfaceControl pipLeash = getLeash(pipChange); final Rect destinationBounds = pipChange.getEndAbsBounds(); @@ -445,6 +445,7 @@ public class PipTransition extends PipTransitionController implements if (pipActivityChange == null) { return false; } + mFinishCallback = finishCallback; final SurfaceControl pipLeash = getLeash(pipChange); final Rect startBounds = pipChange.getStartAbsBounds(); @@ -571,6 +572,7 @@ public class PipTransition extends PipTransitionController implements if (pipChange == null) { return false; } + mFinishCallback = finishCallback; Rect destinationBounds = pipChange.getEndAbsBounds(); SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash(); @@ -613,6 +615,7 @@ public class PipTransition extends PipTransitionController implements return false; } } + mFinishCallback = finishCallback; // The parent change if we were in a multi-activity PiP; null if single activity PiP. final TransitionInfo.Change parentBeforePip = pipChange.getTaskInfo() == null @@ -729,6 +732,10 @@ public class PipTransition extends PipTransitionController implements && getFixedRotationDelta(info, pipTaskChange) == ROTATION_90) { adjustedSourceRectHint.offset(cutoutInsets.left, cutoutInsets.top); } + if (Flags.enableDesktopWindowingPip()) { + adjustedSourceRectHint.offset(-pipActivityChange.getStartAbsBounds().left, + -pipActivityChange.getStartAbsBounds().top); + } } else { // For non-valid app provided src-rect-hint, calculate one to crop into during // app icon overlay animation. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index b922cd029468..0869caa55369 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -550,7 +550,9 @@ public class RecentTasksController implements TaskStackListenerCallback, groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo, mTaskSplitBoundsMap.get(pairedTaskId))); } else { - if (Flags.enableRefactorTaskThumbnail() && isWallpaperTask(taskInfo)) { + if ( + Flags.enableUseTopVisibleActivityForExcludeFromRecentTask() + && isWallpaperTask(taskInfo)) { // Don't add the wallpaper task as an entry in grouped tasks continue; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 37d58780fc85..032dac9ff3a2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -1317,6 +1317,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // otherwise a new transition will notify the relevant observers if (returningToApp && allAppsAreTranslucent(mPausingTasks)) { mHomeTransitionObserver.notifyHomeVisibilityChanged(true); + } else if (!toHome && mState == STATE_NEW_TASK + && allAppsAreTranslucent(mOpeningTasks)) { + // We are opening a translucent app. Launcher is still visible so we do nothing. } else if (!toHome) { // For some transitions, we may have notified home activity that it became // visible. We need to notify the observer that we are no longer going home. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/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..e93ca9e0bd72 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); } @@ -1964,32 +1969,32 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } - int currentSnapPosition = mSplitLayout.calculateCurrentSnapPosition(); - - if (Flags.enableFlexibleTwoAppSplit()) { - // Split screen can be laid out in such a way that some of the apps are offscreen. - // For the purposes of passing SplitBounds up to launcher (for use in thumbnails - // etc.), we crop the bounds down to the screen size. - topLeftBounds.left = - Math.max(topLeftBounds.left, 0); - topLeftBounds.top = - Math.max(topLeftBounds.top, 0); - bottomRightBounds.right = - Math.min(bottomRightBounds.right, mSplitLayout.getDisplayWidth()); - bottomRightBounds.top = - Math.min(bottomRightBounds.top, mSplitLayout.getDisplayHeight()); - - // TODO (b/349828130): Can change to getState() fully after brief soak time. - if (mSplitState.get() != currentSnapPosition) { - Log.wtf(TAG, "SplitState is " + mSplitState.get() - + ", expected " + currentSnapPosition); - currentSnapPosition = mSplitState.get(); + // If all stages are filled, create new SplitBounds and update Recents. + if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) { + int currentSnapPosition = mSplitLayout.calculateCurrentSnapPosition(); + if (Flags.enableFlexibleTwoAppSplit()) { + // Split screen can be laid out in such a way that some of the apps are + // offscreen. For the purposes of passing SplitBounds up to launcher (for use in + // thumbnails etc.), we crop the bounds down to the screen size. + topLeftBounds.left = + Math.max(topLeftBounds.left, 0); + topLeftBounds.top = + Math.max(topLeftBounds.top, 0); + bottomRightBounds.right = + Math.min(bottomRightBounds.right, mSplitLayout.getDisplayWidth()); + bottomRightBounds.top = + Math.min(bottomRightBounds.top, mSplitLayout.getDisplayHeight()); + + // TODO (b/349828130): Can change to getState() fully after brief soak time. + if (mSplitState.get() != currentSnapPosition) { + Log.wtf(TAG, "SplitState is " + mSplitState.get() + + ", expected " + currentSnapPosition); + currentSnapPosition = mSplitState.get(); + } } - } + SplitBounds splitBounds = new SplitBounds(topLeftBounds, bottomRightBounds, + leftTopTaskId, rightBottomTaskId, currentSnapPosition); - SplitBounds splitBounds = new SplitBounds(topLeftBounds, bottomRightBounds, - leftTopTaskId, rightBottomTaskId, currentSnapPosition); - if (mainStageTopTaskId != INVALID_TASK_ID && sideStageTopTaskId != INVALID_TASK_ID) { // Update the pair for the top tasks boolean added = recentTasks.addSplitPair(mainStageTopTaskId, sideStageTopTaskId, splitBounds); @@ -2150,8 +2155,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.setForceTranslucent(mRootTaskInfo.token, translucent); } - /** Callback when split roots visiblility changed. - * NOTICE: This only be called on legacy transition. */ + /** Callback when split roots visiblility changed. */ @Override public void onStageVisibilityChanged(StageTaskListener stageListener) { // If split didn't active, just ignore this callback because we should already did these diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt index 3fa8df40dfef..a92100410d3d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageOrderOperator.kt @@ -95,13 +95,16 @@ class StageOrderOperator ( */ fun onEnteringSplit(@SnapPosition goingToLayout: Int) { if (goingToLayout == currentLayout) { - // Add protolog here. Return for now, but maybe we want to handle swap case, TBD + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "Entering Split requested same layout split is in: %d", goingToLayout) return } val freeStages: List<StageTaskListener> = allStages.filterNot { activeStages.contains(it) } when(goingToLayout) { - SplitScreenConstants.SNAP_TO_2_50_50 -> { + SplitScreenConstants.SNAP_TO_2_50_50, + SplitScreenConstants.SNAP_TO_2_33_66, + SplitScreenConstants.SNAP_TO_2_66_33 -> { if (activeStages.size < 2) { // take from allStages and add into activeStages for (i in 0 until (2 - activeStages.size)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 4a37169add36..f1245ba26cc2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -240,12 +240,20 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { @Override @CallSuper public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: taskId=%d taskAct=%s " - + "stageId=%s", - taskInfo.taskId, taskInfo.baseActivity, stageTypeToString(mId)); + ProtoLog.d(WM_SHELL_SPLIT_SCREEN, + "onTaskInfoChanged: taskId=%d vis=%b reqVis=%b baseAct=%s stageId=%s", + taskInfo.taskId, taskInfo.isVisible, taskInfo.isVisibleRequested, + taskInfo.baseActivity, stageTypeToString(mId)); mWindowDecorViewModel.ifPresent(viewModel -> viewModel.onTaskInfoChanged(taskInfo)); if (mRootTaskInfo.taskId == taskInfo.taskId) { mRootTaskInfo = taskInfo; + boolean isVisible = taskInfo.isVisible && taskInfo.isVisibleRequested; + if (mVisible != isVisible) { + ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: currentVis=%b newVis=%b", + mVisible, isVisible); + mVisible = isVisible; + mCallbacks.onStageVisibilityChanged(this); + } } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { if (!taskInfo.supportsMultiWindow || !ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType()) @@ -260,7 +268,6 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { return; } mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); - mVisible = isStageVisible(); mCallbacks.onChildTaskStatusChanged(this, taskInfo.taskId, true /* present */, taskInfo.isVisible && taskInfo.isVisibleRequested); } else { @@ -309,19 +316,6 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { t.reparent(sc, findTaskSurface(taskId)); } - /** - * Checks against all children task info and return true if any are marked as visible. - */ - private boolean isStageVisible() { - for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { - if (mChildrenTaskInfo.valueAt(i).isVisible - && mChildrenTaskInfo.valueAt(i).isVisibleRequested) { - return true; - } - } - return false; - } - private SurfaceControl findTaskSurface(int taskId) { if (mRootTaskInfo.taskId == taskId) { return mRootLeash; 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/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java index 03ded730865e..b0547a2a47b1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java @@ -204,6 +204,7 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "tryAnimateOpenIntentWithRemoteAndPipOrDesktop"); TransitionInfo.Change pipChange = null; + TransitionInfo.Change pipActivityChange = null; for (int i = info.getChanges().size() - 1; i >= 0; --i) { TransitionInfo.Change change = info.getChanges().get(i); if (mPipHandler.isEnteringPip(change, info.getType())) { @@ -213,6 +214,12 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { } pipChange = change; info.getChanges().remove(i); + } else if (change.getTaskInfo() == null && change.getParent() != null + && pipChange != null && change.getParent().equals(pipChange.getContainer())) { + // Cache the PiP activity if it's a target and cached pip task change is its parent; + // note that we are bottom-to-top, so if such activity has a task + // that is also a target, then it must have been cached already as pipChange. + pipActivityChange = change; } } TransitionInfo.Change desktopChange = null; @@ -257,8 +264,16 @@ class DefaultMixedTransition extends DefaultMixedHandler.MixedTransition { // make a new startTransaction because pip's startEnterAnimation "consumes" it so // we need a separate one to send over to launcher. SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction(); - - mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, finishCB); + if (pipActivityChange == null) { + mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, + finishCB); + } else { + info.getChanges().remove(pipActivityChange); + TransitionInfo pipInfo = subCopy(info, TRANSIT_PIP, false /* withChanges */); + pipInfo.getChanges().addAll(List.of(pipChange, pipActivityChange)); + mPipHandler.startAnimation(mTransition, pipInfo, startTransaction, + finishTransaction, finishCB); + } // Dispatch the rest of the transition normally. if (mLeftoversHandler != null diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 611f3e0ac5e8..a7d6301ecf06 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -1076,9 +1076,11 @@ public class Transitions implements RemoteCallable<Transitions>, @Nullable TransitionHandler skip ) { for (int i = mHandlers.size() - 1; i >= 0; --i) { - if (mHandlers.get(i) == skip) continue; - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " try handler %s", - mHandlers.get(i)); + if (mHandlers.get(i) == skip) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " skip handler %s", + mHandlers.get(i)); + continue; + } boolean consumed = mHandlers.get(i).startAnimation(transition, info, startT, finishT, finishCB); if (consumed) { 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/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 85e3068a09a6..aea4bda527b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -717,7 +717,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // App sometimes draws before the insets from WindowDecoration#relayout have // been added, so they must be added here decoration.addCaptionInset(wct); - mDesktopTasksController.moveTaskToDesktop(taskId, wct, source); + mDesktopTasksController.moveTaskToDesktop(taskId, wct, source, + /* remoteTransition= */ null); decoration.closeHandleMenu(); if (source == DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) { @@ -1634,7 +1635,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } final DesktopModeWindowDecoration windowDecoration = mDesktopModeWindowDecorFactory.create( - mContext, + Flags.enableBugFixesForSecondaryDisplay() + ? mDisplayController.getDisplayContext(taskInfo.displayId) + : mContext, mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */), mDisplayController, mSplitScreenController, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 6562f38e724d..01319fb8c713 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -98,6 +98,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.CaptionState; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; +import com.android.wm.shell.desktopmode.DesktopModeUtils; import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; @@ -522,7 +523,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } else { mWindowDecorViewHolder.bindData(new AppHeaderViewHolder.HeaderData( mTaskInfo, - TaskInfoKt.getRequestingImmersive(mTaskInfo), + DesktopModeUtils.isTaskMaximized(mTaskInfo, mDisplayController), inFullImmersive, hasGlobalFocus, /* maximizeHoverEnabled= */ canOpenMaximizeMenu( @@ -556,10 +557,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @Nullable private Intent getBrowserLink() { final Uri browserLink; - if (isCapturedLinkAvailable()) { - browserLink = mCapturedLink.mUri; - } else if (mWebUri != null) { + if (mWebUri != null) { browserLink = mWebUri; + } else if (isCapturedLinkAvailable()) { + browserLink = mCapturedLink.mUri; } else { browserLink = mGenericLink; } @@ -1316,7 +1317,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ @VisibleForTesting void onAssistContentReceived(@Nullable AssistContent assistContent) { - mWebUri = assistContent == null ? null : assistContent.getWebUri(); + mWebUri = assistContent == null ? null : AppToWebUtils.getSessionWebUri(assistContent); loadAppInfoIfNeeded(); updateGenericLink(); final boolean supportsMultiInstance = mMultiInstanceHelper @@ -1705,7 +1706,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin .isTaskInFullImmersiveState(mTaskInfo.taskId); asAppHeader(mWindowDecorViewHolder).bindData(new AppHeaderViewHolder.HeaderData( mTaskInfo, - TaskInfoKt.getRequestingImmersive(mTaskInfo), + DesktopModeUtils.isTaskMaximized(mTaskInfo, mDisplayController), inFullImmersive, isFocused(), /* maximizeHoverEnabled= */ canOpenMaximizeMenu(animatingTaskResizeOrReposition))); 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/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt index d94391820d05..f3a8b206867d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt @@ -40,12 +40,12 @@ import androidx.compose.ui.graphics.toArgb import androidx.core.content.withStyledAttributes import androidx.core.view.isGone import androidx.core.view.isVisible -import com.android.internal.R.attr.materialColorOnSecondaryContainer -import com.android.internal.R.attr.materialColorOnSurface -import com.android.internal.R.attr.materialColorSecondaryContainer -import com.android.internal.R.attr.materialColorSurfaceContainerHigh -import com.android.internal.R.attr.materialColorSurfaceContainerLow -import com.android.internal.R.attr.materialColorSurfaceDim +import com.android.internal.R.color.materialColorOnSecondaryContainer +import com.android.internal.R.color.materialColorOnSurface +import com.android.internal.R.color.materialColorSecondaryContainer +import com.android.internal.R.color.materialColorSurfaceContainerHigh +import com.android.internal.R.color.materialColorSurfaceContainerLow +import com.android.internal.R.color.materialColorSurfaceDim import com.android.window.flags.Flags import com.android.window.flags.Flags.enableMinimizeButton import com.android.wm.shell.R @@ -79,7 +79,7 @@ class AppHeaderViewHolder( data class HeaderData( val taskInfo: RunningTaskInfo, - val isRequestingImmersive: Boolean, + val isTaskMaximized: Boolean, val inFullImmersiveState: Boolean, val hasGlobalFocus: Boolean, val enableMaximizeLongClick: Boolean, @@ -163,7 +163,7 @@ class AppHeaderViewHolder( override fun bindData(data: HeaderData) { bindData( data.taskInfo, - data.isRequestingImmersive, + data.isTaskMaximized, data.inFullImmersiveState, data.hasGlobalFocus, data.enableMaximizeLongClick @@ -172,7 +172,7 @@ class AppHeaderViewHolder( private fun bindData( taskInfo: RunningTaskInfo, - isRequestingImmersive: Boolean, + isTaskMaximized: Boolean, inFullImmersiveState: Boolean, hasGlobalFocus: Boolean, enableMaximizeLongClick: Boolean, @@ -180,7 +180,7 @@ class AppHeaderViewHolder( if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) { bindDataWithThemedHeaders( taskInfo, - isRequestingImmersive, + isTaskMaximized, inFullImmersiveState, hasGlobalFocus, enableMaximizeLongClick, @@ -225,7 +225,7 @@ class AppHeaderViewHolder( private fun bindDataWithThemedHeaders( taskInfo: RunningTaskInfo, - requestingImmersive: Boolean, + isTaskMaximized: Boolean, inFullImmersiveState: Boolean, hasGlobalFocus: Boolean, enableMaximizeLongClick: Boolean, @@ -283,7 +283,7 @@ class AppHeaderViewHolder( drawableInsets = maximizeDrawableInsets ) ) - setIcon(getMaximizeButtonIcon(requestingImmersive, inFullImmersiveState)) + setIcon(getMaximizeButtonIcon(isTaskMaximized, inFullImmersiveState)) } // Close button. closeWindowButton.apply { @@ -358,34 +358,19 @@ class AppHeaderViewHolder( @DrawableRes private fun getMaximizeButtonIcon( - requestingImmersive: Boolean, + isTaskMaximized: Boolean, inFullImmersiveState: Boolean ): Int = when { - shouldShowEnterFullImmersiveIcon(requestingImmersive, inFullImmersiveState) -> { - R.drawable.decor_desktop_mode_immersive_button_dark - } - shouldShowExitFullImmersiveIcon(requestingImmersive, inFullImmersiveState) -> { - R.drawable.decor_desktop_mode_immersive_exit_button_dark + shouldShowExitFullImmersiveOrMaximizeIcon(isTaskMaximized, inFullImmersiveState) -> { + R.drawable.decor_desktop_mode_immersive_or_maximize_exit_button_dark } else -> R.drawable.decor_desktop_mode_maximize_button_dark } - private fun shouldShowEnterFullImmersiveIcon( - requestingImmersive: Boolean, - inFullImmersiveState: Boolean - ): Boolean = Flags.enableFullyImmersiveInDesktop() - && requestingImmersive && !inFullImmersiveState - - private fun shouldShowExitFullImmersiveIcon( - requestingImmersive: Boolean, - inFullImmersiveState: Boolean - ): Boolean = isInFullImmersiveStateAndRequesting(requestingImmersive, inFullImmersiveState) - - private fun isInFullImmersiveStateAndRequesting( - requestingImmersive: Boolean, + private fun shouldShowExitFullImmersiveOrMaximizeIcon( + isTaskMaximized: Boolean, inFullImmersiveState: Boolean - ): Boolean = Flags.enableFullyImmersiveInDesktop() - && requestingImmersive && inFullImmersiveState + ): Boolean = (Flags.enableFullyImmersiveInDesktop() && inFullImmersiveState) || isTaskMaximized private fun getHeaderStyle(header: Header): HeaderStyle { return HeaderStyle( @@ -595,33 +580,31 @@ class AppHeaderViewHolder( @ColorInt private fun getAppNameAndButtonColor(taskInfo: RunningTaskInfo, hasGlobalFocus: Boolean): Int { - val materialColorAttr = when { + val materialColor = context.getColor(when { taskInfo.isTransparentCaptionBarAppearance && taskInfo.isLightCaptionBarAppearance -> materialColorOnSecondaryContainer taskInfo.isTransparentCaptionBarAppearance && !taskInfo.isLightCaptionBarAppearance -> materialColorOnSurface isDarkMode() -> materialColorOnSurface else -> materialColorOnSecondaryContainer - } + }) val appDetailsOpacity = when { isDarkMode() && !hasGlobalFocus -> DARK_THEME_UNFOCUSED_OPACITY !isDarkMode() && !hasGlobalFocus -> LIGHT_THEME_UNFOCUSED_OPACITY else -> FOCUSED_OPACITY } - context.withStyledAttributes(null, intArrayOf(materialColorAttr), 0, 0) { - val color = getColor(0, 0) - return if (appDetailsOpacity == FOCUSED_OPACITY) { - color - } else { - Color.argb( - appDetailsOpacity, - Color.red(color), - Color.green(color), - Color.blue(color) - ) - } + + + return if (appDetailsOpacity == FOCUSED_OPACITY) { + materialColor + } else { + Color.argb( + appDetailsOpacity, + Color.red(materialColor), + Color.green(materialColor), + Color.blue(materialColor) + ) } - return 0 } private fun isDarkMode(): Boolean { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index f22e2a591df3..47ee7bb20199 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -33,6 +33,8 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -634,7 +636,7 @@ public class BackAnimationControllerTest extends ShellTestCase { releaseBackGesture(); mShellExecutor.flushAll(); - verify(mAppCallback).setHandoffHandler(any()); + verify(mAppCallback).setHandoffHandler(notNull()); } @Test @@ -654,7 +656,7 @@ public class BackAnimationControllerTest extends ShellTestCase { releaseBackGesture(); mShellExecutor.flushAll(); - verify(mAppCallback, never()).setHandoffHandler(any()); + verify(mAppCallback).setHandoffHandler(isNull()); } @Test @@ -716,7 +718,7 @@ public class BackAnimationControllerTest extends ShellTestCase { tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); - verify(mBackTransitionHandler).handlePrepareTransition( + verify(mBackTransitionHandler).handlePrepareTransition(eq(mockBinder), eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.mCloseTransitionRequested = true; TransitionInfo tInfo2 = createTransitionInfo(TRANSIT_CLOSE, close); @@ -748,7 +750,7 @@ public class BackAnimationControllerTest extends ShellTestCase { null /* remoteTransition */); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); - verify(mBackTransitionHandler).handlePrepareTransition( + verify(mBackTransitionHandler).handlePrepareTransition(eq(mockBinder), eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.onAnimationFinished(); @@ -799,7 +801,7 @@ public class BackAnimationControllerTest extends ShellTestCase { canHandle = mBackTransitionHandler.startAnimation(mockBinder, prepareInfo, st, ft, callback2); assertTrue("Handle prepare transition" , canHandle); - verify(mBackTransitionHandler).handlePrepareTransition( + verify(mBackTransitionHandler).handlePrepareTransition(eq(mockBinder), eq(prepareInfo), eq(st), eq(ft), eq(callback2)); final TransitionInfo closeInfo = createTransitionInfo(TRANSIT_CLOSE, close); Transitions.TransitionFinishCallback mergeCallback = @@ -817,7 +819,7 @@ public class BackAnimationControllerTest extends ShellTestCase { canHandle = mBackTransitionHandler.startAnimation( mockBinder, prepareInfo, st, ft, callback3); assertTrue("Handle prepare transition" , canHandle); - verify(mBackTransitionHandler).handlePrepareTransition( + verify(mBackTransitionHandler).handlePrepareTransition(eq(mockBinder), eq(prepareInfo), eq(st), eq(ft), eq(callback3)); final TransitionInfo.Change open2 = createAppChange( openTaskId2, TRANSIT_OPEN, FLAG_MOVED_TO_TOP); 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/common/HandlerExecutorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/HandlerExecutorTest.kt new file mode 100644 index 000000000000..799b48c2504f --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/HandlerExecutorTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.common + +import android.os.Handler +import android.os.HandlerThread +import android.os.Looper +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito +import com.android.wm.shell.ShellTestCase +import com.google.common.truth.Truth.assertThat +import java.util.function.BiConsumer +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.MockitoSession +import org.mockito.kotlin.whenever + +/** + * Tests for HandlerExecutor. + * + * Build/Install/Run: + * atest WMShellUnitTests:HandlerExecutorTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class HandlerExecutorTest : ShellTestCase() { + + class TestSetThreadPriorityFn : BiConsumer<Int, Int> { + var lastSetPriority = UNSET_THREAD_PRIORITY + private set + var callCount = 0 + private set + + override fun accept(tid: Int, priority: Int) { + lastSetPriority = priority + callCount++ + } + + fun reset() { + lastSetPriority = UNSET_THREAD_PRIORITY + callCount = 0 + } + } + + val testSetPriorityFn = TestSetThreadPriorityFn() + + @Test + fun defaultExecutorDisallowBoost() { + val executor = createTestHandlerExecutor() + + executor.setBoost() + + assertThat(executor.isBoosted()).isFalse() + } + + @Test + fun boostExecutor_resetWhenNotSet_expectNoOp() { + val executor = createTestHandlerExecutor(DEFAULT_THREAD_PRIORITY, BOOSTED_THREAD_PRIORITY) + val mockSession: MockitoSession = ExtendedMockito.mockitoSession() + .mockStatic(android.os.Process::class.java) + .startMocking() + + try { + // Try to reset and ensure we never try to set the thread priority + executor.resetBoost() + + assertThat(testSetPriorityFn.callCount).isEqualTo(0) + assertThat(executor.isBoosted()).isFalse() + } finally { + mockSession.finishMocking() + } + } + + @Test + fun boostExecutor_setResetBoost_expectThreadPriorityUpdated() { + val executor = createTestHandlerExecutor(DEFAULT_THREAD_PRIORITY, BOOSTED_THREAD_PRIORITY) + val mockSession: MockitoSession = ExtendedMockito.mockitoSession() + .mockStatic(android.os.Process::class.java) + .startMocking() + + try { + // Boost and ensure the boosted thread priority is requested + executor.setBoost() + + assertThat(testSetPriorityFn.lastSetPriority).isEqualTo(BOOSTED_THREAD_PRIORITY) + assertThat(testSetPriorityFn.callCount).isEqualTo(1) + assertThat(executor.isBoosted()).isTrue() + + // Reset and ensure the default thread priority is requested + executor.resetBoost() + + assertThat(testSetPriorityFn.lastSetPriority).isEqualTo(DEFAULT_THREAD_PRIORITY) + assertThat(testSetPriorityFn.callCount).isEqualTo(2) + assertThat(executor.isBoosted()).isFalse() + } finally { + mockSession.finishMocking() + } + } + + @Test + fun boostExecutor_overlappingBoost_expectResetOnlyWhenNotOverlapping() { + val executor = createTestHandlerExecutor(DEFAULT_THREAD_PRIORITY, BOOSTED_THREAD_PRIORITY) + val mockSession: MockitoSession = ExtendedMockito.mockitoSession() + .mockStatic(android.os.Process::class.java) + .startMocking() + + try { + // Set and ensure we only update the thread priority once + executor.setBoost() + executor.setBoost() + + assertThat(testSetPriorityFn.lastSetPriority).isEqualTo(BOOSTED_THREAD_PRIORITY) + assertThat(testSetPriorityFn.callCount).isEqualTo(1) + assertThat(executor.isBoosted()).isTrue() + + // Reset and ensure we are still boosted and the thread priority doesn't change + executor.resetBoost() + + assertThat(testSetPriorityFn.lastSetPriority).isEqualTo(BOOSTED_THREAD_PRIORITY) + assertThat(testSetPriorityFn.callCount).isEqualTo(1) + assertThat(executor.isBoosted()).isTrue() + + // Reset again and ensure we update the thread priority accordingly + executor.resetBoost() + + assertThat(testSetPriorityFn.lastSetPriority).isEqualTo(DEFAULT_THREAD_PRIORITY) + assertThat(testSetPriorityFn.callCount).isEqualTo(2) + assertThat(executor.isBoosted()).isFalse() + } finally { + mockSession.finishMocking() + } + } + + /** + * Creates a test handler executor backed by a mocked handler thread. + */ + private fun createTestHandlerExecutor( + defaultThreadPriority: Int = DEFAULT_THREAD_PRIORITY, + boostedThreadPriority: Int = DEFAULT_THREAD_PRIORITY + ) : HandlerExecutor { + val handler = mock(Handler::class.java) + val looper = mock(Looper::class.java) + val thread = mock(HandlerThread::class.java) + whenever(handler.looper).thenReturn(looper) + whenever(looper.thread).thenReturn(thread) + whenever(thread.threadId).thenReturn(1234) + val executor = HandlerExecutor(handler, defaultThreadPriority, boostedThreadPriority) + executor.replaceSetThreadPriorityFn(testSetPriorityFn) + return executor + } + + companion object { + private const val UNSET_THREAD_PRIORITY = 0 + private const val DEFAULT_THREAD_PRIORITY = 1 + private const val BOOSTED_THREAD_PRIORITY = 1000 + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java index 94dbd112bb75..4c97c76ae122 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java @@ -19,6 +19,7 @@ package com.android.wm.shell.compatui; import static android.content.res.Configuration.UI_MODE_NIGHT_YES; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.window.flags.Flags.FLAG_APP_COMPAT_ASYNC_RELAYOUT; import static com.android.window.flags.Flags.FLAG_APP_COMPAT_UI_FRAMEWORK; import static com.android.wm.shell.compatui.CompatUIStatusManager.COMPAT_UI_EDUCATION_HIDDEN; import static com.android.wm.shell.compatui.CompatUIStatusManager.COMPAT_UI_EDUCATION_VISIBLE; @@ -42,10 +43,12 @@ import android.app.ActivityManager; import android.app.TaskInfo; import android.graphics.Insets; import android.graphics.Rect; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.util.Pair; import android.view.DisplayCutout; @@ -125,6 +128,9 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback; @Mock private DockStateReader mDockStateReader; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private CompatUIConfiguration mCompatUIConfiguration; private TestShellExecutor mExecutor; private FakeCompatUIStatusManagerTest mCompatUIStatus; @@ -317,6 +323,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) + @DisableFlags(FLAG_APP_COMPAT_ASYNC_RELAYOUT) public void testUpdateCompatInfo_updatesLayoutCorrectly() { LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); @@ -346,6 +353,36 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) + @EnableFlags(FLAG_APP_COMPAT_ASYNC_RELAYOUT) + public void testUpdateCompatInfo_updatesLayoutCorrectlyAsync() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + LetterboxEduDialogLayout layout = windowManager.mLayout; + assertNotNull(layout); + + assertTrue(windowManager.updateCompatInfo( + createTaskInfo(/* eligible= */ true, USER_ID_1, new Rect(50, 25, 150, 75)), + mTaskListener, /* canShow= */ true)); + + verifyLayout(layout, layout.getLayoutParams(), /* expectedWidth= */ 100, + /* expectedHeight= */ 50, /* expectedExtraTopMargin= */ 0, + /* expectedExtraBottomMargin= */ 0); + verify(mViewHost).relayout(mWindowAttrsCaptor.capture(), any()); + assertThat(mWindowAttrsCaptor.getValue()).isEqualTo(layout.getLayoutParams()); + + // Window manager should be released (without animation) when eligible becomes false. + assertFalse(windowManager.updateCompatInfo(createTaskInfo(/* eligible= */ false), + mTaskListener, /* canShow= */ true)); + + verify(windowManager).release(); + verify(mOnDismissCallback, never()).accept(any()); + verify(mAnimationController, never()).startExitAnimation(any(), any()); + assertNull(windowManager.mLayout); + } + + @Test + @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) public void testUpdateCompatInfo_notEligibleUntilUpdate_createsLayoutAfterUpdate() { LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ false); @@ -375,6 +412,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) + @DisableFlags(FLAG_APP_COMPAT_ASYNC_RELAYOUT) public void testUpdateDisplayLayout_updatesLayoutCorrectly() { LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); @@ -397,6 +435,29 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) + @EnableFlags(FLAG_APP_COMPAT_ASYNC_RELAYOUT) + public void testUpdateDisplayLayout_updatesLayoutCorrectlyAsync() { + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); + + assertTrue(windowManager.createLayout(/* canShow= */ true)); + LetterboxEduDialogLayout layout = windowManager.mLayout; + assertNotNull(layout); + + int newDisplayCutoutTop = DISPLAY_CUTOUT_TOP + 7; + int newDisplayCutoutBottom = DISPLAY_CUTOUT_BOTTOM + 9; + windowManager.updateDisplayLayout(createDisplayLayout( + Insets.of(DISPLAY_CUTOUT_HORIZONTAL, newDisplayCutoutTop, + DISPLAY_CUTOUT_HORIZONTAL, newDisplayCutoutBottom))); + + verifyLayout(layout, layout.getLayoutParams(), /* expectedWidth= */ TASK_WIDTH, + /* expectedHeight= */ TASK_HEIGHT, /* expectedExtraTopMargin= */ + newDisplayCutoutTop, /* expectedExtraBottomMargin= */ newDisplayCutoutBottom); + verify(mViewHost).relayout(mWindowAttrsCaptor.capture(), any()); + assertThat(mWindowAttrsCaptor.getValue()).isEqualTo(layout.getLayoutParams()); + } + + @Test + @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRelease_animationIsCancelled() { LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS index 5b05af9b0a74..3a017f38f3ea 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/OWNERS @@ -1,2 +1,8 @@ # Bug component: 970984 -# includes OWNERS from parent directories
\ No newline at end of file +# includes OWNERS from parent directories + +mariiasand@google.com +mcarli@google.com +minagranic@google.com +gracielawputri@google.com +eevlachavas@google.com
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxControllerRobotTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxControllerRobotTest.kt index 95a0c82c76df..88cc981dd30c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxControllerRobotTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxControllerRobotTest.kt @@ -16,10 +16,8 @@ package com.android.wm.shell.compatui.letterbox -import android.content.Context import android.graphics.Rect import android.view.SurfaceControl -import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn import com.android.wm.shell.compatui.letterbox.LetterboxMatchers.asAnyMode import org.mockito.kotlin.any import org.mockito.kotlin.clearInvocations @@ -31,10 +29,7 @@ import org.mockito.kotlin.verify /** * Robot to test [LetterboxController] implementations. */ -open class LetterboxControllerRobotTest( - ctx: Context, - controllerBuilder: (LetterboxSurfaceBuilder) -> LetterboxController -) { +abstract class LetterboxControllerRobotTest { companion object { @JvmStatic @@ -44,21 +39,21 @@ open class LetterboxControllerRobotTest( private val TASK_ID = 20 } - private val letterboxConfiguration: LetterboxConfiguration - private val surfaceBuilder: LetterboxSurfaceBuilder - private val letterboxController: LetterboxController - private val transaction: SurfaceControl.Transaction - private val parentLeash: SurfaceControl + lateinit var letterboxController: LetterboxController + val transaction: SurfaceControl.Transaction + val parentLeash: SurfaceControl init { - letterboxConfiguration = LetterboxConfiguration(ctx) - surfaceBuilder = LetterboxSurfaceBuilder(letterboxConfiguration) - letterboxController = controllerBuilder(surfaceBuilder) transaction = getTransactionMock() parentLeash = mock<SurfaceControl>() - spyOn(surfaceBuilder) } + fun initController() { + letterboxController = buildController() + } + + abstract fun buildController(): LetterboxController + fun sendCreateSurfaceRequest( displayId: Int = DISPLAY_ID, taskId: Int = TASK_ID @@ -102,16 +97,6 @@ open class LetterboxControllerRobotTest( letterboxController.dump() } - fun checkSurfaceBuilderInvoked(times: Int = 1, name: String = "", callSite: String = "") { - verify(surfaceBuilder, times(times)).createSurface( - eq(transaction), - eq(parentLeash), - name.asAnyMode(), - callSite.asAnyMode(), - any() - ) - } - fun checkTransactionRemovedInvoked(times: Int = 1) { verify(transaction, times(times)).remove(any()) } 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..dd4cb1185b31 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 @@ -16,12 +16,16 @@ 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 @@ -39,24 +43,14 @@ import org.mockito.kotlin.verify @SmallTest class LetterboxUtilsTest : ShellTestCase() { - val firstLetterboxController = mock<LetterboxController>() - val secondLetterboxController = mock<LetterboxController>() - val thirdLetterboxController = mock<LetterboxController>() - - private val letterboxControllerBuilder: (LetterboxSurfaceBuilder) -> LetterboxController = - { _ -> - firstLetterboxController.append(secondLetterboxController) - .append(thirdLetterboxController) - } - @Test fun `Appended LetterboxController invoked creation on all the controllers`() { runTestScenario { r -> r.sendCreateSurfaceRequest() - r.verifyCreateSurfaceInvokedWithRequest(target = firstLetterboxController) - r.verifyCreateSurfaceInvokedWithRequest(target = secondLetterboxController) - r.verifyCreateSurfaceInvokedWithRequest(target = thirdLetterboxController) + r.verifyCreateSurfaceInvokedWithRequest(target = r.firstLetterboxController) + r.verifyCreateSurfaceInvokedWithRequest(target = r.secondLetterboxController) + r.verifyCreateSurfaceInvokedWithRequest(target = r.thirdLetterboxController) } } @@ -64,9 +58,9 @@ class LetterboxUtilsTest : ShellTestCase() { fun `Appended LetterboxController invoked destroy on all the controllers`() { runTestScenario { r -> r.sendDestroySurfaceRequest() - r.verifyDestroySurfaceInvokedWithRequest(target = firstLetterboxController) - r.verifyDestroySurfaceInvokedWithRequest(target = secondLetterboxController) - r.verifyDestroySurfaceInvokedWithRequest(target = thirdLetterboxController) + r.verifyDestroySurfaceInvokedWithRequest(target = r.firstLetterboxController) + r.verifyDestroySurfaceInvokedWithRequest(target = r.secondLetterboxController) + r.verifyDestroySurfaceInvokedWithRequest(target = r.thirdLetterboxController) } } @@ -74,9 +68,9 @@ class LetterboxUtilsTest : ShellTestCase() { fun `Appended LetterboxController invoked update visibility on all the controllers`() { runTestScenario { r -> r.sendUpdateSurfaceVisibilityRequest(visible = true) - r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = firstLetterboxController) - r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = secondLetterboxController) - r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = thirdLetterboxController) + r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = r.firstLetterboxController) + r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = r.secondLetterboxController) + r.verifyUpdateVisibilitySurfaceInvokedWithRequest(target = r.thirdLetterboxController) } } @@ -84,9 +78,9 @@ class LetterboxUtilsTest : ShellTestCase() { fun `Appended LetterboxController invoked update bounds on all the controllers`() { runTestScenario { r -> r.sendUpdateSurfaceBoundsRequest(taskBounds = Rect(), activityBounds = Rect()) - r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = firstLetterboxController) - r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = secondLetterboxController) - r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = thirdLetterboxController) + r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = r.firstLetterboxController) + r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = r.secondLetterboxController) + r.verifyUpdateSurfaceBoundsInvokedWithRequest(target = r.thirdLetterboxController) } } @@ -94,9 +88,38 @@ class LetterboxUtilsTest : ShellTestCase() { fun `Appended LetterboxController invoked update dump on all the controllers`() { runTestScenario { r -> r.invokeDump() - r.verifyDumpInvoked(target = firstLetterboxController) - r.verifyDumpInvoked(target = secondLetterboxController) - r.verifyDumpInvoked(target = thirdLetterboxController) + r.verifyDumpInvoked(target = r.firstLetterboxController) + r.verifyDumpInvoked(target = r.secondLetterboxController) + r.verifyDumpInvoked(target = r.thirdLetterboxController) + } + } + + @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) } } @@ -104,14 +127,21 @@ class LetterboxUtilsTest : ShellTestCase() { * Runs a test scenario providing a Robot. */ fun runTestScenario(consumer: Consumer<AppendLetterboxControllerRobotTest>) { - val robot = AppendLetterboxControllerRobotTest(mContext, letterboxControllerBuilder) - consumer.accept(robot) + consumer.accept(AppendLetterboxControllerRobotTest().apply { initController() }) } - class AppendLetterboxControllerRobotTest( - ctx: Context, - builder: (LetterboxSurfaceBuilder) -> LetterboxController - ) : LetterboxControllerRobotTest(ctx, builder) { + class AppendLetterboxControllerRobotTest : LetterboxControllerRobotTest() { + + val firstLetterboxController = mock<LetterboxController>() + val secondLetterboxController = mock<LetterboxController>() + val thirdLetterboxController = mock<LetterboxController>() + + 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 surface = SurfaceControl() fun verifyCreateSurfaceInvokedWithRequest( target: LetterboxController, @@ -147,5 +177,50 @@ 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) + } + + override fun buildController(): LetterboxController = + firstLetterboxController.append(secondLetterboxController) + .append(thirdLetterboxController) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MixedLetterboxControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MixedLetterboxControllerTest.kt index e6bff4c1ec15..3b72ff1cac71 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MixedLetterboxControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MixedLetterboxControllerTest.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.compatui.letterbox -import android.content.Context import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase @@ -64,65 +63,48 @@ class MixedLetterboxControllerTest : ShellTestCase() { * Runs a test scenario providing a Robot. */ fun runTestScenario(consumer: Consumer<MixedLetterboxControllerRobotTest>) { - val robot = MixedLetterboxControllerRobotTest(mContext, ObjectToTestHolder()) - consumer.accept(robot) + consumer.accept(MixedLetterboxControllerRobotTest().apply { initController() }) } - class MixedLetterboxControllerRobotTest( - ctx: Context, - private val objectToTestHolder: ObjectToTestHolder - ) : LetterboxControllerRobotTest(ctx, objectToTestHolder.controllerBuilder) { + class MixedLetterboxControllerRobotTest : LetterboxControllerRobotTest() { + val singleLetterboxController: SingleSurfaceLetterboxController = + mock<SingleSurfaceLetterboxController>() + val multipleLetterboxController: MultiSurfaceLetterboxController = + mock<MultiSurfaceLetterboxController>() + val controllerStrategy: LetterboxControllerStrategy = mock<LetterboxControllerStrategy>() fun configureStrategyFor(letterboxMode: LetterboxMode) { - doReturn(letterboxMode).`when`(objectToTestHolder.controllerStrategy) - .getLetterboxImplementationMode() + doReturn(letterboxMode).`when`(controllerStrategy).getLetterboxImplementationMode() } fun checkCreateInvokedOnSingleController(times: Int = 1) { - verify( - objectToTestHolder.singleLetterboxController, - times(times) - ).createLetterboxSurface(any(), any(), any()) + verify(singleLetterboxController, times(times)).createLetterboxSurface( + any(), + any(), + any() + ) } fun checkCreateInvokedOnMultiController(times: Int = 1) { - verify( - objectToTestHolder.multipleLetterboxController, - times(times) - ).createLetterboxSurface(any(), any(), any()) + verify(multipleLetterboxController, times(times)).createLetterboxSurface( + any(), + any(), + any() + ) } fun checkDestroyInvokedOnSingleController(times: Int = 1) { - verify( - objectToTestHolder.singleLetterboxController, - times(times) - ).destroyLetterboxSurface(any(), any()) + verify(singleLetterboxController, times(times)).destroyLetterboxSurface(any(), any()) } fun checkDestroyInvokedOnMultiController(times: Int = 1) { - verify( - objectToTestHolder.multipleLetterboxController, - times(times) - ).destroyLetterboxSurface(any(), any()) + verify(multipleLetterboxController, times(times)).destroyLetterboxSurface(any(), any()) } - } - - data class ObjectToTestHolder( - val singleLetterboxController: SingleSurfaceLetterboxController = - mock<SingleSurfaceLetterboxController>(), - val multipleLetterboxController: MultiSurfaceLetterboxController = - mock<MultiSurfaceLetterboxController>(), - val controllerStrategy: LetterboxControllerStrategy = mock<LetterboxControllerStrategy>() - ) { - - private val mixedController = - MixedLetterboxController( - singleLetterboxController, - multipleLetterboxController, - controllerStrategy - ) - val controllerBuilder: (LetterboxSurfaceBuilder) -> LetterboxController = - { _ -> mixedController } + override fun buildController(): LetterboxController = MixedLetterboxController( + singleLetterboxController, + multipleLetterboxController, + controllerStrategy + ) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxControllerTest.kt index 295d4edf206b..3fd837db478c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxControllerTest.kt @@ -16,13 +16,20 @@ package com.android.wm.shell.compatui.letterbox +import android.content.Context import android.graphics.Rect import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.compatui.letterbox.LetterboxMatchers.asAnyMode import java.util.function.Consumer import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.times +import org.mockito.kotlin.verify /** * Tests for [MultiSurfaceLetterboxController]. @@ -147,9 +154,33 @@ class MultiSurfaceLetterboxControllerTest : ShellTestCase() { /** * Runs a test scenario providing a Robot. */ - fun runTestScenario(consumer: Consumer<LetterboxControllerRobotTest>) { - val robot = - LetterboxControllerRobotTest(mContext, { sb -> MultiSurfaceLetterboxController(sb) }) - consumer.accept(robot) + fun runTestScenario(consumer: Consumer<MultiLetterboxControllerRobotTest>) { + consumer.accept(MultiLetterboxControllerRobotTest(mContext).apply { initController() }) + } + + class MultiLetterboxControllerRobotTest(context: Context) : + LetterboxControllerRobotTest() { + + private val letterboxConfiguration: LetterboxConfiguration + private val surfaceBuilder: LetterboxSurfaceBuilder + + init { + letterboxConfiguration = LetterboxConfiguration(context) + surfaceBuilder = LetterboxSurfaceBuilder(letterboxConfiguration) + spyOn(surfaceBuilder) + } + + override fun buildController(): LetterboxController = + MultiSurfaceLetterboxController(surfaceBuilder) + + fun checkSurfaceBuilderInvoked(times: Int = 1, name: String = "", callSite: String = "") { + verify(surfaceBuilder, times(times)).createSurface( + eq(transaction), + eq(parentLeash), + name.asAnyMode(), + callSite.asAnyMode(), + any() + ) + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxControllerTest.kt index 125e700bcd42..e6ffe98875ed 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxControllerTest.kt @@ -16,13 +16,20 @@ package com.android.wm.shell.compatui.letterbox +import android.content.Context import android.graphics.Rect import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.compatui.letterbox.LetterboxMatchers.asAnyMode import java.util.function.Consumer import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.times +import org.mockito.kotlin.verify /** * Tests for [SingleSurfaceLetterboxController]. @@ -120,9 +127,33 @@ class SingleSurfaceLetterboxControllerTest : ShellTestCase() { /** * Runs a test scenario providing a Robot. */ - fun runTestScenario(consumer: Consumer<LetterboxControllerRobotTest>) { - val robot = - LetterboxControllerRobotTest(mContext, { sb -> SingleSurfaceLetterboxController(sb) }) - consumer.accept(robot) + fun runTestScenario(consumer: Consumer<SingleLetterboxControllerRobotTest>) { + consumer.accept(SingleLetterboxControllerRobotTest(mContext).apply { initController() }) + } + + class SingleLetterboxControllerRobotTest(context: Context) : + LetterboxControllerRobotTest() { + + private val letterboxConfiguration: LetterboxConfiguration + private val surfaceBuilder: LetterboxSurfaceBuilder + + init { + letterboxConfiguration = LetterboxConfiguration(context) + surfaceBuilder = LetterboxSurfaceBuilder(letterboxConfiguration) + spyOn(surfaceBuilder) + } + + override fun buildController(): LetterboxController = + SingleSurfaceLetterboxController(surfaceBuilder) + + fun checkSurfaceBuilderInvoked(times: Int = 1, name: String = "", callSite: String = "") { + verify(surfaceBuilder, times(times)).createSurface( + eq(transaction), + eq(parentLeash), + name.asAnyMode(), + callSite.asAnyMode(), + any() + ) + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index 41a594a3347a..4cc641cd1d81 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -36,6 +36,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE import com.android.window.flags.Flags.FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor @@ -98,6 +99,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Mock lateinit var persistentRepository: DesktopPersistentRepository @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer @Mock lateinit var userManager: UserManager + @Mock lateinit var shellController: ShellController private lateinit var mockitoSession: StaticMockitoSession private lateinit var handler: DesktopActivityOrientationChangeHandler @@ -123,6 +125,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { DesktopUserRepositories( context, shellInit, + shellController, persistentRepository, repositoryInitializer, testScope, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt index db4c7465ae48..b87f20023796 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt @@ -42,6 +42,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.desktopmode.DesktopImmersiveController.Direction import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitReason.USER_INTERACTION import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.sysui.ShellInit @@ -88,13 +89,15 @@ class DesktopImmersiveControllerTest : ShellTestCase() { @Before fun setUp() { userRepositories = DesktopUserRepositories( - context, ShellInit(TestShellExecutor()), mock(), mock(), mock(), mock() + context, ShellInit(TestShellExecutor()), mock(), mock(), mock(), mock(), mock() ) whenever(mockDisplayController.getDisplayLayout(DEFAULT_DISPLAY)) .thenReturn(mockDisplayLayout) whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { invocation -> (invocation.getArgument(0) as Rect).set(STABLE_BOUNDS) } + whenever(mockDisplayLayout.width()).thenReturn(DISPLAY_BOUNDS.width()) + whenever(mockDisplayLayout.height()).thenReturn(DISPLAY_BOUNDS.height()) controller = DesktopImmersiveController( shellInit = mock(), transitions = mockTransitions, @@ -277,10 +280,12 @@ class DesktopImmersiveControllerTest : ShellTestCase() { controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isTrue() + assertTransitionPending( + transition = transition, + taskId = task.taskId, + direction = Direction.EXIT, + animate = false + ) } @Test @@ -298,10 +303,12 @@ class DesktopImmersiveControllerTest : ShellTestCase() { controller.exitImmersiveIfApplicable(transition, wct, DEFAULT_DISPLAY, USER_INTERACTION) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isFalse() + assertTransitionNotPending( + transition = transition, + taskId = task.taskId, + direction = Direction.EXIT, + animate = false + ) } @Test @@ -360,10 +367,12 @@ class DesktopImmersiveControllerTest : ShellTestCase() { reason = USER_INTERACTION, ).asExit()?.runOnTransitionStart?.invoke(transition) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isFalse() + assertTransitionNotPending( + transition = transition, + taskId = task.taskId, + animate = false, + direction = Direction.EXIT + ) } @Test @@ -416,10 +425,12 @@ class DesktopImmersiveControllerTest : ShellTestCase() { controller.exitImmersiveIfApplicable(wct, task, USER_INTERACTION) .asExit()?.runOnTransitionStart?.invoke(transition) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isTrue() + assertTransitionPending( + transition = transition, + taskId = task.taskId, + direction = Direction.EXIT, + animate = false + ) } @Test @@ -481,10 +492,12 @@ class DesktopImmersiveControllerTest : ShellTestCase() { ) controller.onTransitionFinished(transition, aborted = false) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isFalse() + assertTransitionNotPending( + transition = transition, + taskId = task.taskId, + direction = Direction.EXIT, + animate = false + ) } @Test @@ -513,14 +526,18 @@ class DesktopImmersiveControllerTest : ShellTestCase() { controller.onTransitionMerged(transition, mergedToTransition) controller.onTransitionFinished(mergedToTransition, aborted = false) - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == transition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isFalse() - assertThat(controller.pendingExternalExitTransitions.any { exit -> - exit.transition == mergedToTransition && exit.displayId == DEFAULT_DISPLAY - && exit.taskId == task.taskId - }).isFalse() + assertTransitionNotPending( + transition = transition, + taskId = task.taskId, + animate = false, + direction = Direction.EXIT + ) + assertTransitionNotPending( + transition = mergedToTransition, + taskId = task.taskId, + animate = false, + direction = Direction.EXIT + ) } @Test @@ -686,7 +703,7 @@ class DesktopImmersiveControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) - fun externalAnimateResizeChange_doesNotCleanUpPendingTransitionState() { + fun externalAnimateResizeChange_doesNotRemovePendingTransition() { val task = createFreeformTask() val mockBinder = mock(IBinder::class.java) whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(controller))) @@ -709,12 +726,16 @@ class DesktopImmersiveControllerTest : ShellTestCase() { ) animatorTestRule.advanceTimeBy(DesktopImmersiveController.FULL_IMMERSIVE_ANIM_DURATION_MS) - assertThat(controller.state).isNotNull() + assertTransitionPending( + transition = mockBinder, + taskId = task.taskId, + direction = Direction.EXIT + ) } @Test @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) - fun startAnimation_missingChange_clearsState() { + fun startAnimation_missingChange_removesPendingTransition() { val task = createFreeformTask() val mockBinder = mock(IBinder::class.java) whenever(mockTransitions.startTransition(eq(TRANSIT_CHANGE), any(), eq(controller))) @@ -735,7 +756,42 @@ class DesktopImmersiveControllerTest : ShellTestCase() { finishCallback = {} ) - assertThat(controller.state).isNull() + assertTransitionNotPending( + transition = mockBinder, + taskId = task.taskId, + direction = Direction.ENTER + ) + } + + private fun assertTransitionPending( + transition: IBinder, + taskId: Int, + direction: Direction, + animate: Boolean = true, + displayId: Int = DEFAULT_DISPLAY + ) { + assertThat(controller.pendingImmersiveTransitions.any { pendingTransition -> + pendingTransition.transition == transition + && pendingTransition.displayId == displayId + && pendingTransition.taskId == taskId + && pendingTransition.animate == animate + && pendingTransition.direction == direction + }).isTrue() + } + + private fun assertTransitionNotPending( + transition: IBinder, + taskId: Int, + direction: Direction, + animate: Boolean = true, + displayId: Int = DEFAULT_DISPLAY + ) { + assertThat(controller.pendingImmersiveTransitions.any { pendingTransition -> + pendingTransition.transition == transition + && pendingTransition.displayId == displayId + && pendingTransition.taskId == taskId + && pendingTransition.direction == direction + }).isFalse() } private fun createTransitionInfo( @@ -768,5 +824,6 @@ class DesktopImmersiveControllerTest : ShellTestCase() { companion object { private val STABLE_BOUNDS = Rect(0, 100, 2000, 1900) + private val DISPLAY_BOUNDS = Rect(0, 0, 2000, 2000) } } 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 3bee588feee9..cf16e42a729b 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 @@ -21,6 +21,7 @@ import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityOptions import android.app.KeyguardManager import android.app.PendingIntent +import android.app.PictureInPictureParams import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM @@ -275,6 +276,7 @@ class DesktopTasksControllerTest : ShellTestCase() { DesktopUserRepositories( context, shellInit, + shellController, persistentRepository, repositoryInitializer, testScope, @@ -1216,14 +1218,40 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun moveRunningTaskToDesktop_deviceSupported_taskIsMovedToDesktop() { - val task = setUpFullscreenTask() + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + fun moveBackgroundTaskToDesktop_remoteTransition_usesOneShotHandler() { + val transitionHandlerArgCaptor = ArgumentCaptor.forClass(TransitionHandler::class.java) + whenever( + transitions.startTransition(anyInt(), any(), transitionHandlerArgCaptor.capture()) + ).thenReturn(Binder()) - controller.moveRunningTaskToDesktop(task, transitionSource = UNKNOWN) + val task = createTaskInfo(1) + whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null) + whenever(recentTasksController.findTaskInBackground(anyInt())).thenReturn(task) + controller.moveTaskToDesktop( + taskId = task.taskId, + transitionSource = UNKNOWN, + remoteTransition = RemoteTransition(spy(TestRemoteTransition()))) - val wct = getLatestEnterDesktopWct() - assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM) verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION) + assertIs<OneShotRemoteHandler>(transitionHandlerArgCaptor.value) + } + + + @Test + fun moveRunningTaskToDesktop_remoteTransition_usesOneShotHandler() { + val transitionHandlerArgCaptor = ArgumentCaptor.forClass(TransitionHandler::class.java) + whenever( + transitions.startTransition(anyInt(), any(), transitionHandlerArgCaptor.capture()) + ).thenReturn(Binder()) + + controller.moveRunningTaskToDesktop( + task = setUpFullscreenTask(), + transitionSource = UNKNOWN, + remoteTransition = RemoteTransition(spy(TestRemoteTransition()))) + + verify(desktopModeEnterExitTransitionListener).onEnterDesktopModeTransitionStarted(FREEFORM_ANIMATION_DURATION) + assertIs<OneShotRemoteHandler>(transitionHandlerArgCaptor.value) } @Test @@ -1724,6 +1752,34 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun onDesktopWindowMinimize_pipTask_autoEnterEnabled_startPipTransition() { + val task = setUpPipTask(autoEnterEnabled = true) + val handler = mock(TransitionHandler::class.java) + whenever(freeformTaskTransitionStarter.startPipTransition(any())) + .thenReturn(Binder()) + whenever(transitions.dispatchRequest(any(), any(), anyOrNull())) + .thenReturn(android.util.Pair(handler, WindowContainerTransaction()) + ) + + controller.minimizeTask(task) + + verify(freeformTaskTransitionStarter).startPipTransition(any()) + verify(freeformTaskTransitionStarter, never()).startMinimizedModeTransition(any()) + } + + @Test + fun onDesktopWindowMinimize_pipTask_autoEnterDisabled_startMinimizeTransition() { + val task = setUpPipTask(autoEnterEnabled = false) + whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) + .thenReturn(Binder()) + + controller.minimizeTask(task) + + verify(freeformTaskTransitionStarter).startMinimizedModeTransition(any()) + verify(freeformTaskTransitionStarter, never()).startPipTransition(any()) + } + + @Test fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() { val task = setUpFreeformTask(active = true) val transition = Binder() @@ -3033,20 +3089,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( @@ -3851,7 +3908,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun shellController_registersUserChangeListener() { - verify(shellController, times(1)).addUserChangeListener(any()) + verify(shellController, times(2)).addUserChangeListener(any()) } @Test @@ -4228,6 +4285,14 @@ class DesktopTasksControllerTest : ShellTestCase() { return task } + private fun setUpPipTask(autoEnterEnabled: Boolean): RunningTaskInfo { + return setUpFreeformTask().apply { + pictureInPictureParams = PictureInPictureParams.Builder() + .setAutoEnterEnabled(autoEnterEnabled) + .build() + } + } + private fun setUpHomeTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createHomeTask(displayId) whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index 0712d58166bb..39178cb2cd25 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -42,6 +42,7 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository @@ -96,6 +97,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Mock lateinit var persistentRepository: DesktopPersistentRepository @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer @Mock lateinit var userManager: UserManager + @Mock lateinit var shellController: ShellController private lateinit var mockitoSession: StaticMockitoSession private lateinit var desktopTasksLimiter: DesktopTasksLimiter @@ -117,6 +119,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { DesktopUserRepositories( context, shellInit, + shellController, persistentRepository, repositoryInitializer, testScope, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt index 5767df4c5a8e..a2e939d86adb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt @@ -24,14 +24,15 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest -import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -66,6 +67,7 @@ class DesktopUserRepositoriesTest : ShellTestCase() { private val persistentRepository = mock<DesktopPersistentRepository>() private val repositoryInitializer = mock<DesktopRepositoryInitializer>() private val userManager = mock<UserManager>() + private val shellController = mock<ShellController>() @Before fun setUp() { @@ -86,8 +88,14 @@ class DesktopUserRepositoriesTest : ShellTestCase() { whenever(userManager.getProfiles(USER_ID_1)).thenReturn(profiles) userRepositories = DesktopUserRepositories( - context, shellInit, persistentRepository, repositoryInitializer, datastoreScope, - userManager) + context, + shellInit, + shellController, + persistentRepository, + repositoryInitializer, + datastoreScope, + userManager + ) } @After diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt index 1c88a290d677..cdf064b075a1 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt @@ -27,6 +27,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopUserRepositories +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -64,6 +65,7 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { private val persistentRepository = mock<DesktopPersistentRepository>() private val userManager = mock<UserManager>() private val testExecutor = mock<ShellExecutor>() + private val shellController = mock<ShellController>() @Before fun setUp() { @@ -74,7 +76,12 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { DesktopRepositoryInitializerImpl(context, persistentRepository, datastoreScope) desktopUserRepositories = DesktopUserRepositories( - context, shellInit, persistentRepository, repositoryInitializer, datastoreScope, + context, + shellInit, + shellController, + persistentRepository, + repositoryInitializer, + datastoreScope, userManager ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index c6835b7bde55..22b45e8c63af 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -22,7 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static com.android.launcher3.Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL; +import static com.android.launcher3.Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE; import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50; @@ -250,7 +250,7 @@ public class RecentTasksControllerTest extends ShellTestCase { t3.taskId, -1); } - @EnableFlags(FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @EnableFlags(FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) @Test public void testGetRecentTasks_removesDesktopWallpaperActivity() { RecentTaskInfo t1 = makeTaskInfo(1); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageOrderOperatorTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageOrderOperatorTests.kt new file mode 100644 index 000000000000..3b4a86a71d90 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageOrderOperatorTests.kt @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.splitscreen + +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.icons.IconProvider +import com.android.wm.shell.Flags.enableFlexibleSplit +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_33_66 +import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50 +import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_66_33 +import com.android.wm.shell.splitscreen.StageTaskListener.StageListenerCallbacks +import com.android.wm.shell.windowdecor.WindowDecorViewModel +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import java.util.Optional + +@SmallTest +@RunWith(AndroidJUnit4::class) +class StageOrderOperatorTests : ShellTestCase() { + + @Mock + lateinit var mTaskOrganizer: ShellTaskOrganizer + @Mock + lateinit var mSyncQueue: SyncTransactionQueue + @Mock + lateinit var stageListenerCallbacks: StageListenerCallbacks + @Mock + lateinit var iconProvider: IconProvider + @Mock + lateinit var windowDecorViewModel: Optional<WindowDecorViewModel> + + lateinit var stageOrderOperator: StageOrderOperator + + @Before + fun setup() { + stageOrderOperator = StageOrderOperator( + context, + mTaskOrganizer, + DEFAULT_DISPLAY, + stageListenerCallbacks, + mSyncQueue, + iconProvider, + windowDecorViewModel, + ) + assert(stageOrderOperator.activeStages.size == 0) + } + + @Test + fun activeStages_2_2app_50_50_split() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_50_50) + assert(stageOrderOperator.activeStages.size == 2) + } + + @Test + fun activeStages_2_2app_33_66_split() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_33_66) + assert(stageOrderOperator.activeStages.size == 2) + } + + @Test + fun activeStages_2_2app_66_33_split() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + assert(stageOrderOperator.activeStages.size == 2) + } + + @Test + fun activateSameCountStage_noOp() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + assert(stageOrderOperator.activeStages.size == 2) + } + + @Test + fun deactivate_emptyActiveStages() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + stageOrderOperator.onExitingSplit() + assert(stageOrderOperator.activeStages.isEmpty()) + } + + @Test + fun swapDividerPos_twoApps() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + val stageIndex0: StageTaskListener = stageOrderOperator.activeStages[0] + val stageIndex1: StageTaskListener = stageOrderOperator.activeStages[1] + + stageOrderOperator.onDoubleTappedDivider() + val newStageIndex0: StageTaskListener = stageOrderOperator.activeStages[0] + val newStageIndex1: StageTaskListener = stageOrderOperator.activeStages[1] + + assert(stageIndex0 == newStageIndex1) + assert(stageIndex1 == newStageIndex0) + } + + @Test + fun swapDividerPos_twiceNoOp_twoApps() { + assumeTrue(enableFlexibleSplit()) + + stageOrderOperator.onEnteringSplit(SNAP_TO_2_66_33) + val stageIndex0: StageTaskListener = stageOrderOperator.activeStages[0] + val stageIndex1: StageTaskListener = stageOrderOperator.activeStages[1] + + stageOrderOperator.onDoubleTappedDivider() + stageOrderOperator.onDoubleTappedDivider() + val newStageIndex0: StageTaskListener = stageOrderOperator.activeStages[0] + val newStageIndex1: StageTaskListener = stageOrderOperator.activeStages[1] + + assert(stageIndex0 == newStageIndex0) + assert(stageIndex1 == newStageIndex1) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt index e871711fd25e..cf6c3a5e03a0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt @@ -63,6 +63,7 @@ class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { userRepositories = DesktopUserRepositories( context = context, shellInit = ShellInit(TestShellExecutor()), + shellController = mock(), persistentRepository = mock(), repositoryInitializer = mock(), mainCoroutineScope = mock(), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 88f62d10913d..0214da4660ad 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -388,7 +388,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest } @Test - fun testOnDecorMaximizedOrRestored_togglesTaskSize() { + fun testOnDecorMaximizedOrRestored_togglesTaskSize_maximize() { val maxOrRestoreListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> val decor = createOpenTaskDecoration( @@ -409,6 +409,52 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest } @Test + fun testOnDecorMaximizedOrRestored_togglesTaskSize_maximizeFromMaximizedSize() { + val maxOrRestoreListenerCaptor = forClass(Function0::class.java) + as ArgumentCaptor<Function0<Unit>> + val decor = createOpenTaskDecoration( + windowingMode = WINDOWING_MODE_FREEFORM, + onMaxOrRestoreListenerCaptor = maxOrRestoreListenerCaptor + ) + val movedMaximizedBounds = Rect(STABLE_BOUNDS) + movedMaximizedBounds.offset(10, 10) + decor.mTaskInfo.configuration.windowConfiguration.bounds.set(movedMaximizedBounds) + + maxOrRestoreListenerCaptor.value.invoke() + + verify(mockDesktopTasksController).toggleDesktopTaskSize( + decor.mTaskInfo, + ToggleTaskSizeInteraction( + ToggleTaskSizeInteraction.Direction.MAXIMIZE, + ToggleTaskSizeInteraction.Source.MAXIMIZE_MENU_TO_MAXIMIZE, + InputMethod.UNKNOWN_INPUT_METHOD + ) + ) + } + + @Test + fun testOnDecorMaximizedOrRestored_togglesTaskSize_restore() { + val maxOrRestoreListenerCaptor = forClass(Function0::class.java) + as ArgumentCaptor<Function0<Unit>> + val decor = createOpenTaskDecoration( + windowingMode = WINDOWING_MODE_FREEFORM, + onMaxOrRestoreListenerCaptor = maxOrRestoreListenerCaptor + ) + decor.mTaskInfo.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS) + + maxOrRestoreListenerCaptor.value.invoke() + + verify(mockDesktopTasksController).toggleDesktopTaskSize( + decor.mTaskInfo, + ToggleTaskSizeInteraction( + ToggleTaskSizeInteraction.Direction.RESTORE, + ToggleTaskSizeInteraction.Source.MAXIMIZE_MENU_TO_RESTORE, + InputMethod.UNKNOWN_INPUT_METHOD + ) + ) + } + + @Test fun testOnDecorMaximizedOrRestored_closesMenus() { val maxOrRestoreListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> @@ -591,7 +637,8 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest verify(mockDesktopTasksController).moveTaskToDesktop( eq(decor.mTaskInfo.taskId), any(), - eq(DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON) + eq(DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON), + anyOrNull() ) } @@ -824,7 +871,7 @@ class DesktopModeWindowDecorViewModelTests : DesktopModeWindowDecorViewModelTest ) verify(mockDesktopTasksController, times(1)) - .moveTaskToDesktop(any(), any(), any()) + .moveTaskToDesktop(any(), any(), any(), anyOrNull()) } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt index 6be234ef5ca6..7a37c5eec604 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt @@ -149,7 +149,6 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { protected val mockCaptionHandleRepository = mock<WindowDecorCaptionHandleRepository>() protected val mockDesktopRepository: DesktopRepository = mock<DesktopRepository>() protected val motionEvent = mock<MotionEvent>() - val displayController = mock<DisplayController>() val displayLayout = mock<DisplayLayout>() protected lateinit var spyContext: TestableContext private lateinit var desktopModeEventLogger: DesktopModeEventLogger @@ -255,7 +254,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { argumentCaptor<DesktopModeKeyguardChangeListener>() verify(mockShellController).addKeyguardChangeListener(keyguardChangedCaptor.capture()) desktopModeOnKeyguardChangedListener = keyguardChangedCaptor.firstValue - whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) + whenever(mockDisplayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> (i.arguments.first() as Rect).set(STABLE_BOUNDS) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 5d5d1f220ae0..db7b1f22768f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.assist.AssistContent.EXTRA_SESSION_TRANSFER_WEB_URI; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; @@ -157,6 +158,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private static final Uri TEST_URI1 = Uri.parse("https://www.google.com/"); private static final Uri TEST_URI2 = Uri.parse("https://docs.google.com/"); private static final Uri TEST_URI3 = Uri.parse("https://slides.google.com/"); + private static final Uri TEST_URI4 = Uri.parse("https://calendar.google.com/"); @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @@ -1322,11 +1324,11 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) - public void capturedLink_handleMenuBrowserLinkSetToCapturedLinkIfValid() { + public void capturedLink_CapturedLinkUsedIfValidAndWebUriUnavailable() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( - taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, - TEST_URI3 /* generic link */); + taskInfo, TEST_URI1 /* captured link */, null /* web uri */, + null /* session transfer uri */, TEST_URI4 /* generic link */); // Verify handle menu's browser link set as captured link createHandleMenu(decor); @@ -1339,7 +1341,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, null /* web uri */, - null /* generic link */); + null /* session transfer uri */, null /* generic link */); final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = ArgumentCaptor.forClass(Function1.class); @@ -1373,7 +1375,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, null /* web uri */, - null /* generic link */); + null /* session transfer uri */, null /* generic link */); final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = ArgumentCaptor.forClass(Function1.class); @@ -1406,7 +1408,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, null /* web uri */, - null /* generic link */); + null /* session transfer uri */, null /* generic link */); final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = ArgumentCaptor.forClass(Function1.class); createHandleMenu(decor); @@ -1432,11 +1434,23 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) - public void webUriLink_webUriLinkUsedWhenCapturedLinkUnavailable() { + public void webUriLink_webUriLinkUsedWhenWhenAvailable() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( - taskInfo, null /* captured link */, TEST_URI2 /* web uri */, - TEST_URI3 /* generic link */); + taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, + TEST_URI3 /* session transfer uri */, TEST_URI4 /* generic link */); + // Verify handle menu's browser link set as web uri link when captured link is unavailable + createHandleMenu(decor); + verifyHandleMenuCreated(TEST_URI3); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) + public void webUriLink_webUriLinkUsedWhenSessionTransferUriUnavailable() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); + final DesktopModeWindowDecoration decor = createWindowDecoration( + taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, + null /* session transfer uri */, TEST_URI4 /* generic link */); // Verify handle menu's browser link set as web uri link when captured link is unavailable createHandleMenu(decor); verifyHandleMenuCreated(TEST_URI2); @@ -1448,12 +1462,12 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, null /* captured link */, null /* web uri */, - TEST_URI3 /* generic link */); + null /* session transfer uri */, TEST_URI4 /* generic link */); // Verify handle menu's browser link set as generic link when captured link and web uri link // are unavailable createHandleMenu(decor); - verifyHandleMenuCreated(TEST_URI3); + verifyHandleMenuCreated(TEST_URI4); } @Test @@ -1637,7 +1651,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) - public void browserApp_webUriUsedForBrowserApp() { + public void browserApp_transferSessionUriUsedForBrowserAppWhenAvailable() { // Make {@link AppToWebUtils#isBrowserApp} return true ResolveInfo resolveInfo = new ResolveInfo(); resolveInfo.handleAllWebDataURI = true; @@ -1648,7 +1662,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, - TEST_URI3 /* generic link */); + null /* transfer session uri */, TEST_URI4 /* generic link */); // Verify web uri used for browser applications createHandleMenu(decor); @@ -1656,6 +1670,27 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB) + public void browserApp_webUriUsedForBrowserAppWhenTransferSessionUriUnavailable() { + // Make {@link AppToWebUtils#isBrowserApp} return true + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.handleAllWebDataURI = true; + resolveInfo.activityInfo = createActivityInfo(); + when(mMockPackageManager.queryIntentActivitiesAsUser(any(), anyInt(), anyInt())) + .thenReturn(List.of(resolveInfo)); + + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */); + final DesktopModeWindowDecoration decor = createWindowDecoration( + taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */, + TEST_URI3 /* transfer session uri */, TEST_URI4 /* generic link */); + + // Verify web uri used for browser applications + createHandleMenu(decor); + verifyHandleMenuCreated(TEST_URI3); + } + + private void verifyHandleMenuCreated(@Nullable Uri uri) { verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), @@ -1692,10 +1727,11 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private DesktopModeWindowDecoration createWindowDecoration( ActivityManager.RunningTaskInfo taskInfo, @Nullable Uri capturedLink, - @Nullable Uri webUri, @Nullable Uri genericLink) { + @Nullable Uri webUri, @Nullable Uri sessionTransferUri, @Nullable Uri genericLink) { taskInfo.capturedLink = capturedLink; taskInfo.capturedLinkTimestamp = System.currentTimeMillis(); mAssistContent.setWebUri(webUri); + mAssistContent.getExtras().putObject(EXTRA_SESSION_TRANSFER_WEB_URI, sessionTransferUri); final String genericLinkString = genericLink == null ? null : genericLink.toString(); doReturn(genericLinkString).when(mMockGenericLinksParser).getGenericLink(any()); // Relayout to set captured link 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/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index b41f40f412d2..5689df0784f0 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -548,8 +548,45 @@ public final class AudioDeviceInfo { return counts; } + /** @hide */ + @IntDef(flag = true, prefix = "AudioFormat.CHANNEL_OUT_", value = { + AudioFormat.CHANNEL_INVALID, + AudioFormat.CHANNEL_OUT_DEFAULT, + AudioFormat.CHANNEL_OUT_FRONT_LEFT, + AudioFormat.CHANNEL_OUT_FRONT_RIGHT, + AudioFormat.CHANNEL_OUT_FRONT_CENTER, + AudioFormat.CHANNEL_OUT_LOW_FREQUENCY, + AudioFormat.CHANNEL_OUT_BACK_LEFT, + AudioFormat.CHANNEL_OUT_BACK_RIGHT, + AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER, + AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER, + AudioFormat.CHANNEL_OUT_BACK_CENTER, + AudioFormat.CHANNEL_OUT_SIDE_LEFT, + AudioFormat.CHANNEL_OUT_SIDE_RIGHT, + AudioFormat.CHANNEL_OUT_TOP_CENTER, + AudioFormat.CHANNEL_OUT_TOP_FRONT_LEFT, + AudioFormat.CHANNEL_OUT_TOP_FRONT_CENTER, + AudioFormat.CHANNEL_OUT_TOP_FRONT_RIGHT, + AudioFormat.CHANNEL_OUT_TOP_BACK_LEFT, + AudioFormat.CHANNEL_OUT_TOP_BACK_CENTER, + AudioFormat.CHANNEL_OUT_TOP_BACK_RIGHT, + AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT, + AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT, + AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT, + AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_CENTER, + AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT, + AudioFormat.CHANNEL_OUT_LOW_FREQUENCY_2, + AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT, + AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT} + ) + @Retention(RetentionPolicy.SOURCE) + @FlaggedApi(FLAG_SPEAKER_LAYOUT_API) + public @interface SpeakerLayoutChannelMask {} + /** - * @return A ChannelMask representing the physical output speaker layout of the device. + * @return A ChannelMask representing the speaker layout of a TYPE_BUILTIN_SPEAKER device. + * + * Valid only for speakers built-in to the device. * * The layout channel mask only indicates which speaker channels are present, the * physical layout of the speakers should be informed by a standard for multi-channel @@ -557,6 +594,7 @@ public final class AudioDeviceInfo { * @see AudioFormat */ @FlaggedApi(FLAG_SPEAKER_LAYOUT_API) + @SpeakerLayoutChannelMask public int getSpeakerLayoutChannelMask() { return mPort.speakerLayoutChannelMask(); } diff --git a/media/java/android/media/IMediaRoute2ProviderService.aidl b/media/java/android/media/IMediaRoute2ProviderService.aidl index eee3d22c7252..714cacb8d326 100644 --- a/media/java/android/media/IMediaRoute2ProviderService.aidl +++ b/media/java/android/media/IMediaRoute2ProviderService.aidl @@ -33,6 +33,23 @@ oneway interface IMediaRoute2ProviderService { void requestCreateSession(long requestId, String packageName, String routeId, in @nullable Bundle sessionHints); + /** + * Requests the creation of a system media routing session. + * + * @param requestId The id of the request. + * @param uid The uid of the package whose media to route, or + * {@link android.os.Process#INVALID_UID} if routing should not be restricted to a specific + * uid. + * @param packageName The name of the package whose media to route. + * @param routeId The id of the route to be initially selected. + * @param sessionHints An optional bundle with parameters. + */ + void requestCreateSystemMediaSession( + long requestId, + int uid, + String packageName, + String routeId, + in @nullable Bundle sessionHints); void selectRoute(long requestId, String sessionId, String routeId); void deselectRoute(long requestId, String sessionId, String routeId); void transferToRoute(long requestId, String sessionId, String routeId); diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index a3ad340f6ef4..037b97a61b3f 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -917,6 +917,17 @@ public final class MediaRoute2Info implements Parcelable { } /** + * Returns whether this route supports routing of the system media. + * + * @hide + */ + public boolean supportsSystemMediaRouting() { + return (mRoutingTypeFlags + & (FLAG_ROUTING_TYPE_SYSTEM_VIDEO | FLAG_ROUTING_TYPE_SYSTEM_AUDIO)) + != 0; + } + + /** * Returns true if the route info has all of the required field. * A route is valid if and only if it is obtained from * {@link com.android.server.media.MediaRouterService}. diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index 547099f044b2..09f40e005b4c 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -18,14 +18,21 @@ package android.media; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static java.util.Objects.requireNonNull; + +import android.Manifest; import android.annotation.CallSuper; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.app.Service; import android.content.Intent; +import android.media.audiopolicy.AudioMix; +import android.media.audiopolicy.AudioMixingRule; +import android.media.audiopolicy.AudioPolicy; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -36,6 +43,7 @@ import android.os.RemoteException; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.util.LongSparseArray; import com.android.internal.annotations.GuardedBy; import com.android.media.flags.Flags; @@ -47,7 +55,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Deque; import java.util.List; -import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -83,8 +90,7 @@ public abstract class MediaRoute2ProviderService extends Service { public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService"; /** - * {@link Intent} action that indicates that the declaring service supports routing of the - * system media. + * A category that indicates that the declaring service supports routing of the system media. * * <p>Providers must include this action if they intend to publish routes that support the * system media, as described by {@link MediaRoute2Info#getSupportedRoutingTypes()}. @@ -94,7 +100,7 @@ public abstract class MediaRoute2ProviderService extends Service { */ // TODO: b/362507305 - Unhide once the implementation and CTS are in place. @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) - @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY) public static final String SERVICE_INTERFACE_SYSTEM_MEDIA = "android.media.MediaRoute2ProviderService.SYSTEM_MEDIA"; @@ -165,6 +171,16 @@ public abstract class MediaRoute2ProviderService extends Service { @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) public static final int REASON_UNIMPLEMENTED = 5; + /** + * The request has failed because the provider has failed to route system media. + * + * @see #notifyRequestFailed + * @hide + */ + // TODO: b/362507305 - Unhide once the implementation and CTS are in place. + @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) + public static final int REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA = 6; + /** @hide */ @IntDef( prefix = "REASON_", @@ -174,7 +190,8 @@ public abstract class MediaRoute2ProviderService extends Service { REASON_NETWORK_ERROR, REASON_ROUTE_NOT_AVAILABLE, REASON_INVALID_COMMAND, - REASON_UNIMPLEMENTED + REASON_UNIMPLEMENTED, + REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA }) @Retention(RetentionPolicy.SOURCE) public @interface Reason {} @@ -187,15 +204,28 @@ public abstract class MediaRoute2ProviderService extends Service { private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false); private final AtomicBoolean mSessionUpdateScheduled = new AtomicBoolean(false); private MediaRoute2ProviderServiceStub mStub; + /** Populated by system_server in {@link #setCallback}. Monotonically non-null. */ private IMediaRoute2ProviderServiceCallback mRemoteCallback; private volatile MediaRoute2ProviderInfo mProviderInfo; @GuardedBy("mRequestIdsLock") private final Deque<Long> mRequestIds = new ArrayDeque<>(MAX_REQUEST_IDS_SIZE); + /** + * Maps system media session creation request ids to a package uid whose media to route. The + * value may be {@link Process#INVALID_UID} for routing sessions that don't affect a specific + * package (for example, if they affect the entire system). + */ + @GuardedBy("mRequestIdsLock") + private final LongSparseArray<Integer> mSystemMediaSessionCreationRequests = + new LongSparseArray<>(); + @GuardedBy("mSessionLock") private final ArrayMap<String, RoutingSessionInfo> mSessionInfos = new ArrayMap<>(); + @GuardedBy("mSessionLock") + private final ArrayMap<String, MediaStreams> mOngoingMediaStreams = new ArrayMap<>(); + public MediaRoute2ProviderService() { mHandler = new Handler(Looper.getMainLooper()); } @@ -282,7 +312,7 @@ public abstract class MediaRoute2ProviderService extends Service { */ public final void notifySessionCreated(long requestId, @NonNull RoutingSessionInfo sessionInfo) { - Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + requireNonNull(sessionInfo, "sessionInfo must not be null"); if (DEBUG) { Log.d(TAG, "notifySessionCreated: Creating a session. requestId=" + requestId @@ -326,17 +356,129 @@ public abstract class MediaRoute2ProviderService extends Service { * @param formats the {@link MediaStreamsFormats} that describes the format for the {@link * MediaStreams} to return. * @return a {@link MediaStreams} instance that holds the media streams to route as part of the - * newly created routing session. + * newly created routing session. May be null if system media capture failed, in which case + * you can ignore the return value, as you will receive a call to {@link #onReleaseSession} + * where you can clean up this session * @hide */ // TODO: b/362507305 - Unhide once the implementation and CTS are in place. @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) - @NonNull + @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) + @Nullable public final MediaStreams notifySystemMediaSessionCreated( long requestId, @NonNull RoutingSessionInfo sessionInfo, @NonNull MediaStreamsFormats formats) { - throw new UnsupportedOperationException(); + requireNonNull(sessionInfo, "sessionInfo must not be null"); + requireNonNull(formats, "formats must not be null"); + if (DEBUG) { + Log.d( + TAG, + "notifySystemMediaSessionCreated: Creating a session. requestId=" + + requestId + + ", sessionInfo=" + + sessionInfo); + } + + Integer uid; + synchronized (mRequestIdsLock) { + uid = mSystemMediaSessionCreationRequests.get(requestId); + mSystemMediaSessionCreationRequests.remove(requestId); + } + + if (uid == null) { + throw new IllegalStateException( + "Unexpected system routing session created (request id=" + + requestId + + "):" + + sessionInfo); + } + + if (mRemoteCallback == null) { + throw new IllegalStateException("Unexpected: remote callback is null."); + } + + int routingTypes = 0; + var providerInfo = mProviderInfo; + for (String selectedRouteId : sessionInfo.getSelectedRoutes()) { + MediaRoute2Info route = providerInfo.mRoutes.get(selectedRouteId); + if (route == null) { + throw new IllegalArgumentException( + "Invalid selected route with id: " + selectedRouteId); + } + routingTypes |= route.getSupportedRoutingTypes(); + } + + if ((routingTypes & MediaRoute2Info.FLAG_ROUTING_TYPE_SYSTEM_AUDIO) == 0) { + // TODO: b/380431086 - Populate video stream once we add support for video. + throw new IllegalArgumentException( + "Selected routes for system media don't support any system media routing" + + " types."); + } + + AudioFormat audioFormat = formats.mAudioFormat; + var mediaStreamsBuilder = new MediaStreams.Builder(); + if (audioFormat != null) { + populateAudioStream(audioFormat, uid, mediaStreamsBuilder); + } + // TODO: b/380431086 - Populate video stream once we add support for video. + + MediaStreams streams = mediaStreamsBuilder.build(); + var audioRecord = streams.mAudioRecord; + if (audioRecord == null) { + Log.e( + TAG, + "Audio record is not populated. Returning an empty stream and scheduling the" + + " session release for: " + + sessionInfo); + mHandler.post(() -> onReleaseSession(REQUEST_ID_NONE, sessionInfo.getOriginalId())); + notifyRequestFailed(requestId, REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA); + return null; + } + + synchronized (mSessionLock) { + try { + mRemoteCallback.notifySessionCreated(requestId, sessionInfo); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + mOngoingMediaStreams.put(sessionInfo.getOriginalId(), streams); + return streams; + } + } + + @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) + private void populateAudioStream( + AudioFormat audioFormat, int uid, MediaStreams.Builder builder) { + var audioAttributes = + new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(); + var audioMixingRuleBuilder = + new AudioMixingRule.Builder() + .addRule(audioAttributes, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE); + if (uid != Process.INVALID_UID) { + audioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid); + } + + AudioMix mix = + new AudioMix.Builder(audioMixingRuleBuilder.build()) + .setFormat(audioFormat) + .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK) + .build(); + AudioPolicy audioPolicy = + new AudioPolicy.Builder(this).setLooper(mHandler.getLooper()).addMix(mix).build(); + var audioManager = getSystemService(AudioManager.class); + if (audioManager == null) { + Log.e(TAG, "Couldn't fetch the audio manager."); + return; + } + audioManager.registerAudioPolicy(audioPolicy); + var audioRecord = audioPolicy.createAudioRecordSink(mix); + if (audioRecord == null) { + Log.e(TAG, "Audio record creation failed."); + audioManager.unregisterAudioPolicy(audioPolicy); + return; + } + builder.setAudioStream(audioPolicy, audioRecord); } /** @@ -344,7 +486,7 @@ public abstract class MediaRoute2ProviderService extends Service { * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed. */ public final void notifySessionUpdated(@NonNull RoutingSessionInfo sessionInfo) { - Objects.requireNonNull(sessionInfo, "sessionInfo must not be null"); + requireNonNull(sessionInfo, "sessionInfo must not be null"); if (DEBUG) { Log.d(TAG, "notifySessionUpdated: Updating session id=" + sessionInfo); @@ -379,6 +521,7 @@ public abstract class MediaRoute2ProviderService extends Service { RoutingSessionInfo sessionInfo; synchronized (mSessionLock) { sessionInfo = mSessionInfos.remove(sessionId); + maybeReleaseMediaStreams(sessionId); if (sessionInfo == null) { Log.w(TAG, "notifySessionReleased: Ignoring unknown session info."); @@ -396,6 +539,34 @@ public abstract class MediaRoute2ProviderService extends Service { } } + /** Releases any system media routing resources associated with the given {@code sessionId}. */ + private void maybeReleaseMediaStreams(String sessionId) { + if (!Flags.enableMirroringInMediaRouter2()) { + return; + } + synchronized (mSessionLock) { + var streams = mOngoingMediaStreams.remove(sessionId); + if (streams != null) { + releaseAudioStream(streams.mAudioPolicy, streams.mAudioRecord); + // TODO: b/380431086: Release the video stream once implemented. + } + } + } + + // We cannot reach the code that requires MODIFY_AUDIO_ROUTING without holding it. + @SuppressWarnings("MissingPermission") + private void releaseAudioStream(AudioPolicy audioPolicy, AudioRecord audioRecord) { + if (audioPolicy == null) { + return; + } + var audioManager = getSystemService(AudioManager.class); + if (audioManager == null) { + return; + } + audioRecord.stop(); + audioManager.unregisterAudioPolicy(audioPolicy); + } + /** * Notifies to the client that the request has failed. * @@ -569,7 +740,7 @@ public abstract class MediaRoute2ProviderService extends Service { * Updates routes of the provider and notifies the system media router service. */ public final void notifyRoutes(@NonNull Collection<MediaRoute2Info> routes) { - Objects.requireNonNull(routes, "routes must not be null"); + requireNonNull(routes, "routes must not be null"); List<MediaRoute2Info> sanitizedRoutes = new ArrayList<>(routes.size()); for (MediaRoute2Info route : routes) { @@ -763,6 +934,32 @@ public abstract class MediaRoute2ProviderService extends Service { } @Override + public void requestCreateSystemMediaSession( + long requestId, + int uid, + String packageName, + String routeId, + @Nullable Bundle sessionHints) { + if (!checkCallerIsSystem()) { + return; + } + if (!checkRouteIdIsValid(routeId, "requestCreateSession")) { + return; + } + synchronized (mRequestIdsLock) { + mSystemMediaSessionCreationRequests.put(requestId, uid); + } + mHandler.sendMessage( + obtainMessage( + MediaRoute2ProviderService::onCreateSystemRoutingSession, + MediaRoute2ProviderService.this, + requestId, + packageName, + routeId, + sessionHints)); + } + + @Override public void selectRoute(long requestId, String sessionId, String routeId) { if (!checkCallerIsSystem()) { return; @@ -825,6 +1022,10 @@ public abstract class MediaRoute2ProviderService extends Service { if (!checkSessionIdIsValid(sessionId, "releaseSession")) { return; } + // We proactively release the system media routing once the system requests it, to + // ensure it happens immediately. + maybeReleaseMediaStreams(sessionId); + addRequestId(requestId); mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession, MediaRoute2ProviderService.this, requestId, sessionId)); @@ -843,12 +1044,14 @@ public abstract class MediaRoute2ProviderService extends Service { @FlaggedApi(Flags.FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) public static final class MediaStreams { - private final AudioRecord mAudioRecord; + @Nullable private final AudioPolicy mAudioPolicy; + @Nullable private final AudioRecord mAudioRecord; // TODO: b/380431086: Add the video equivalent. - private MediaStreams(AudioRecord mAudioRecord) { - this.mAudioRecord = mAudioRecord; + private MediaStreams(Builder builder) { + this.mAudioPolicy = builder.mAudioPolicy; + this.mAudioRecord = builder.mAudioRecord; } /** @@ -859,8 +1062,33 @@ public abstract class MediaRoute2ProviderService extends Service { public AudioRecord getAudioRecord() { return mAudioRecord; } + + /** + * Builder for {@link MediaStreams}. + * + * @hide + */ + public static final class Builder { + + @Nullable private AudioPolicy mAudioPolicy; + @Nullable private AudioRecord mAudioRecord; + + /** Populates system media audio-related structures. */ + public Builder setAudioStream( + @NonNull AudioPolicy audioPolicy, @NonNull AudioRecord audioRecord) { + mAudioPolicy = requireNonNull(audioPolicy); + mAudioRecord = requireNonNull(audioRecord); + return this; + } + + /** Builds a {@link MediaStreams} instance. */ + public MediaStreams build() { + return new MediaStreams(this); + } + } } + /** * Holds the formats to encode media data to be read from {@link MediaStreams}. * @@ -911,7 +1139,7 @@ public abstract class MediaRoute2ProviderService extends Service { */ @NonNull public Builder setAudioFormat(@NonNull AudioFormat audioFormat) { - this.mAudioFormat = Objects.requireNonNull(audioFormat); + this.mAudioFormat = requireNonNull(audioFormat); return this; } diff --git a/media/java/android/media/quality/ActiveProcessingPicture.aidl b/media/java/android/media/quality/ActiveProcessingPicture.aidl new file mode 100644 index 000000000000..2851306f6e4d --- /dev/null +++ b/media/java/android/media/quality/ActiveProcessingPicture.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.quality; + +parcelable ActiveProcessingPicture;
\ No newline at end of file diff --git a/media/java/android/media/quality/ActiveProcessingPicture.java b/media/java/android/media/quality/ActiveProcessingPicture.java new file mode 100644 index 000000000000..e16ad62e23f2 --- /dev/null +++ b/media/java/android/media/quality/ActiveProcessingPicture.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.quality; + +import android.annotation.FlaggedApi; +import android.media.tv.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +/** + * Active picture represents an image or video undergoing picture processing which uses a picture + * profile. The picture profile is used to configure the picture processing parameters. + */ +@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) +public final class ActiveProcessingPicture implements Parcelable { + private final int mId; + private final String mProfileId; + + public ActiveProcessingPicture(int id, @NonNull String profileId) { + mId = id; + mProfileId = profileId; + } + + /** @hide */ + ActiveProcessingPicture(Parcel in) { + mId = in.readInt(); + mProfileId = in.readString(); + } + + @NonNull + public static final Creator<ActiveProcessingPicture> CREATOR = new Creator<>() { + @Override + public ActiveProcessingPicture createFromParcel(Parcel in) { + return new ActiveProcessingPicture(in); + } + + @Override + public ActiveProcessingPicture[] newArray(int size) { + return new ActiveProcessingPicture[size]; + } + }; + + /** + * An ID that uniquely identifies the active content. + * + * <p>The ID is assigned by the system to distinguish different active contents. + */ + public int getId() { + return mId; + } + + /** + * The ID of the picture profile used to configure the content. + */ + @NonNull + public String getProfileId() { + return mProfileId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mId); + dest.writeString(mProfileId); + } +} diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl index 9daebca98e3e..253c2d896d63 100644 --- a/media/java/android/media/quality/IMediaQualityManager.aidl +++ b/media/java/android/media/quality/IMediaQualityManager.aidl @@ -25,51 +25,56 @@ import android.media.quality.PictureProfileHandle; import android.media.quality.PictureProfile; import android.media.quality.SoundProfileHandle; import android.media.quality.SoundProfile; +import android.os.UserHandle; /** * Interface for Media Quality Manager * @hide */ interface IMediaQualityManager { - PictureProfile createPictureProfile(in PictureProfile pp, int userId); - void updatePictureProfile(in String id, in PictureProfile pp, int userId); - void removePictureProfile(in String id, int userId); - PictureProfile getPictureProfile(in int type, in String name, int userId); - List<PictureProfile> getPictureProfilesByPackage(in String packageName, int userId); - List<PictureProfile> getAvailablePictureProfiles(int userId); - boolean setDefaultPictureProfile(in String id, int userId); - List<String> getPictureProfilePackageNames(int userId); - List<String> getPictureProfileAllowList(int userId); - void setPictureProfileAllowList(in List<String> packages, int userId); - List<PictureProfileHandle> getPictureProfileHandle(in String[] id, int userId); + PictureProfile createPictureProfile(in PictureProfile pp, in UserHandle user); + void updatePictureProfile(in String id, in PictureProfile pp, in UserHandle user); + void removePictureProfile(in String id, in UserHandle user); + boolean setDefaultPictureProfile(in String id, in UserHandle user); + PictureProfile getPictureProfile( + in int type, in String name, in boolean includeParams, in UserHandle user); + List<PictureProfile> getPictureProfilesByPackage( + in String packageName, in boolean includeParams, in UserHandle user); + List<PictureProfile> getAvailablePictureProfiles(in boolean includeParams, in UserHandle user); + List<String> getPictureProfilePackageNames(in UserHandle user); + List<String> getPictureProfileAllowList(in UserHandle user); + void setPictureProfileAllowList(in List<String> packages, in UserHandle user); + List<PictureProfileHandle> getPictureProfileHandle(in String[] id, in UserHandle user); - SoundProfile createSoundProfile(in SoundProfile pp, int userId); - void updateSoundProfile(in String id, in SoundProfile pp, int userId); - void removeSoundProfile(in String id, int userId); - SoundProfile getSoundProfile(in int type, in String name, int userId); - List<SoundProfile> getSoundProfilesByPackage(in String packageName, int userId); - List<SoundProfile> getAvailableSoundProfiles(int userId); - boolean setDefaultSoundProfile(in String id, int userId); - List<String> getSoundProfilePackageNames(int userId); - List<String> getSoundProfileAllowList(int userId); - void setSoundProfileAllowList(in List<String> packages, int userId); - List<SoundProfileHandle> getSoundProfileHandle(in String[] id, int userId); + SoundProfile createSoundProfile(in SoundProfile pp, in UserHandle user); + void updateSoundProfile(in String id, in SoundProfile pp, in UserHandle user); + void removeSoundProfile(in String id, in UserHandle user); + boolean setDefaultSoundProfile(in String id, in UserHandle user); + SoundProfile getSoundProfile( + in int type, in String name, in boolean includeParams, in UserHandle user); + List<SoundProfile> getSoundProfilesByPackage( + in String packageName, in boolean includeParams, in UserHandle user); + List<SoundProfile> getAvailableSoundProfiles(in boolean includeParams, in UserHandle user); + List<String> getSoundProfilePackageNames(in UserHandle user); + List<String> getSoundProfileAllowList(in UserHandle user); + void setSoundProfileAllowList(in List<String> packages, in UserHandle user); + List<SoundProfileHandle> getSoundProfileHandle(in String[] id, in UserHandle user); void registerPictureProfileCallback(in IPictureProfileCallback cb); void registerSoundProfileCallback(in ISoundProfileCallback cb); void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb); - List<ParamCapability> getParamCapabilities(in List<String> names, int userId); + List<ParamCapability> getParamCapabilities(in List<String> names, in UserHandle user); - boolean isSupported(int userId); - void setAutoPictureQualityEnabled(in boolean enabled, int userId); - boolean isAutoPictureQualityEnabled(int userId); - void setSuperResolutionEnabled(in boolean enabled, int userId); - boolean isSuperResolutionEnabled(int userId); - void setAutoSoundQualityEnabled(in boolean enabled, int userId); - boolean isAutoSoundQualityEnabled(int userId); + boolean isSupported(in UserHandle user); + void setAutoPictureQualityEnabled(in boolean enabled, in UserHandle user); + boolean isAutoPictureQualityEnabled(in UserHandle user); + void setSuperResolutionEnabled(in boolean enabled, in UserHandle user); + boolean isSuperResolutionEnabled(in UserHandle user); + void setAutoSoundQualityEnabled(in boolean enabled, in UserHandle user); + boolean isAutoSoundQualityEnabled(in UserHandle user); - void setAmbientBacklightSettings(in AmbientBacklightSettings settings, int userId); - void setAmbientBacklightEnabled(in boolean enabled, int userId); - boolean isAmbientBacklightEnabled(int userId); + void setAmbientBacklightSettings(in AmbientBacklightSettings settings, in UserHandle user); + void setAmbientBacklightEnabled(in boolean enabled, in UserHandle user); + boolean isAmbientBacklightEnabled(in UserHandle user); } diff --git a/media/java/android/media/quality/IPictureProfileCallback.aidl b/media/java/android/media/quality/IPictureProfileCallback.aidl index 34aa2b061caf..7071a1684fa2 100644 --- a/media/java/android/media/quality/IPictureProfileCallback.aidl +++ b/media/java/android/media/quality/IPictureProfileCallback.aidl @@ -29,5 +29,5 @@ oneway interface IPictureProfileCallback { void onPictureProfileUpdated(in String id, in PictureProfile p); void onPictureProfileRemoved(in String id, in PictureProfile p); void onParamCapabilitiesChanged(in String id, in List<ParamCapability> caps); - void onError(in int err); + void onError(in String id, in int err); } diff --git a/media/java/android/media/quality/ISoundProfileCallback.aidl b/media/java/android/media/quality/ISoundProfileCallback.aidl index 9043757316bc..30bb106ef34c 100644 --- a/media/java/android/media/quality/ISoundProfileCallback.aidl +++ b/media/java/android/media/quality/ISoundProfileCallback.aidl @@ -29,5 +29,5 @@ oneway interface ISoundProfileCallback { void onSoundProfileUpdated(in String id, in SoundProfile p); void onSoundProfileRemoved(in String id, in SoundProfile p); void onParamCapabilitiesChanged(in String id, in List<ParamCapability> caps); - void onError(in int err); + void onError(in String id, in int err); } diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java index efbe47ba2f22..7e87462b64de 100644 --- a/media/java/android/media/quality/MediaQualityManager.java +++ b/media/java/android/media/quality/MediaQualityManager.java @@ -20,11 +20,13 @@ import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.media.tv.flags.Flags; import android.os.RemoteException; +import android.os.UserHandle; import androidx.annotation.RequiresPermission; @@ -47,7 +49,7 @@ public final class MediaQualityManager { private final IMediaQualityManager mService; private final Context mContext; - private final int mUserId; + private final UserHandle mUserHandle; private final Object mLock = new Object(); // @GuardedBy("mLock") private final List<PictureProfileCallbackRecord> mPpCallbackRecords = new ArrayList<>(); @@ -55,6 +57,9 @@ public final class MediaQualityManager { private final List<SoundProfileCallbackRecord> mSpCallbackRecords = new ArrayList<>(); // @GuardedBy("mLock") private final List<AmbientBacklightCallbackRecord> mAbCallbackRecords = new ArrayList<>(); + // @GuardedBy("mLock") + private final List<ActiveProcessingPictureListenerRecord> mApListenerRecords = + new ArrayList<>(); /** @@ -62,7 +67,7 @@ public final class MediaQualityManager { */ public MediaQualityManager(Context context, IMediaQualityManager service) { mContext = context; - mUserId = context.getUserId(); + mUserHandle = context.getUser(); mService = service; IPictureProfileCallback ppCallback = new IPictureProfileCallback.Stub() { @Override @@ -102,11 +107,11 @@ public final class MediaQualityManager { } } @Override - public void onError(int err) { + public void onError(String profileId, int err) { synchronized (mLock) { for (PictureProfileCallbackRecord record : mPpCallbackRecords) { // TODO: filter callback record - record.postError(err); + record.postError(profileId, err); } } } @@ -149,11 +154,11 @@ public final class MediaQualityManager { } } @Override - public void onError(int err) { + public void onError(String profileId, int err) { synchronized (mLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { // TODO: filter callback record - record.postError(err); + record.postError(profileId, err); } } } @@ -210,18 +215,21 @@ public final class MediaQualityManager { } } - /** * Gets picture profile by given profile type and name. * + * @param type the type of the profile. + * @param name the name of the profile. + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. * @return the corresponding picture profile if available; {@code null} if the name doesn't - * exist. + * exist. */ @Nullable public PictureProfile getPictureProfile( - @PictureProfile.ProfileType int type, @NonNull String name) { + @PictureProfile.ProfileType int type, @NonNull String name, boolean includeParams) { try { - return mService.getPictureProfile(type, name, mUserId); + return mService.getPictureProfile(type, name, includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -231,14 +239,18 @@ public final class MediaQualityManager { /** * Gets profiles that available to the given package. * + * @param packageName the package name of the profiles. + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. * @hide */ @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) - public List<PictureProfile> getPictureProfilesByPackage(@NonNull String packageName) { + public List<PictureProfile> getPictureProfilesByPackage( + @NonNull String packageName, boolean includeParams) { try { - return mService.getPictureProfilesByPackage(packageName, mUserId); + return mService.getPictureProfilesByPackage(packageName, includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -246,11 +258,16 @@ public final class MediaQualityManager { /** * Gets profiles that available to the caller. + * + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. + * @return the corresponding picture profile if available; {@code null} if the name doesn't + * exist. */ @NonNull - public List<PictureProfile> getAvailablePictureProfiles() { + public List<PictureProfile> getAvailablePictureProfiles(boolean includeParams) { try { - return mService.getAvailablePictureProfiles(mUserId); + return mService.getAvailablePictureProfiles(includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -268,7 +285,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public boolean setDefaultPictureProfile(@Nullable String id) { try { - return mService.setDefaultPictureProfile(id, mUserId); + return mService.setDefaultPictureProfile(id, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -277,7 +294,7 @@ public final class MediaQualityManager { /** * Gets all package names whose picture profiles are available. * - * @see #getPictureProfilesByPackage(String) + * @see #getPictureProfilesByPackage(String, boolean) * @hide */ @SystemApi @@ -285,7 +302,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public List<String> getPictureProfilePackageNames() { try { - return mService.getPictureProfilePackageNames(mUserId); + return mService.getPictureProfilePackageNames(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -297,7 +314,7 @@ public final class MediaQualityManager { */ public List<PictureProfileHandle> getPictureProfileHandle(String[] id) { try { - return mService.getPictureProfileHandle(id, mUserId); + return mService.getPictureProfileHandle(id, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -309,7 +326,7 @@ public final class MediaQualityManager { */ public List<SoundProfileHandle> getSoundProfileHandle(String[] id) { try { - return mService.getSoundProfileHandle(id, mUserId); + return mService.getSoundProfileHandle(id, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -320,10 +337,12 @@ public final class MediaQualityManager { * * <p>If the profile is created successfully, * {@link PictureProfileCallback#onPictureProfileAdded(String, PictureProfile)} is invoked. + * + * @param pp the {@link PictureProfile} object to be created. */ public void createPictureProfile(@NonNull PictureProfile pp) { try { - mService.createPictureProfile(pp, mUserId); + mService.createPictureProfile(pp, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -332,10 +351,13 @@ public final class MediaQualityManager { /** * Updates an existing picture profile and store it in the system. + * + * @param profileId the id of the object to be updated. + * @param pp the {@link PictureProfile} object to be updated. */ public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) { try { - mService.updatePictureProfile(profileId, pp, mUserId); + mService.updatePictureProfile(profileId, pp, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -344,10 +366,12 @@ public final class MediaQualityManager { /** * Removes a picture profile from the system. + * + * @param profileId the id of the object to be removed. */ public void removePictureProfile(@NonNull String profileId) { try { - mService.removePictureProfile(profileId, mUserId); + mService.removePictureProfile(profileId, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -383,18 +407,20 @@ public final class MediaQualityManager { } } - /** * Gets sound profile by given profile type and name. * - * @return the corresponding sound profile if available; {@code null} if the name doesn't - * exist. + * @param type the type of the profile. + * @param name the name of the profile. + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. + * @return the corresponding sound profile if available; {@code null} if the name doesn't exist. */ @Nullable public SoundProfile getSoundProfile( - @SoundProfile.ProfileType int type, @NonNull String name) { + @SoundProfile.ProfileType int type, @NonNull String name, boolean includeParams) { try { - return mService.getSoundProfile(type, name, mUserId); + return mService.getSoundProfile(type, name, includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -404,14 +430,18 @@ public final class MediaQualityManager { /** * Gets profiles that available to the given package. * + * @param packageName the package name of the profiles. + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. * @hide */ @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) - public List<SoundProfile> getSoundProfilesByPackage(@NonNull String packageName) { + public List<SoundProfile> getSoundProfilesByPackage( + @NonNull String packageName, boolean includeParams) { try { - return mService.getSoundProfilesByPackage(packageName, mUserId); + return mService.getSoundProfilesByPackage(packageName, includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -419,11 +449,16 @@ public final class MediaQualityManager { /** * Gets profiles that available to the caller package. + * + * @param includeParams {@code true} to include parameters in the profile; {@code false} + * otherwise. + * + * @return the corresponding sound profile if available; {@code null} if the none available. */ @NonNull - public List<SoundProfile> getAvailableSoundProfiles() { + public List<SoundProfile> getAvailableSoundProfiles(boolean includeParams) { try { - return mService.getAvailableSoundProfiles(mUserId); + return mService.getAvailableSoundProfiles(includeParams, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -441,7 +476,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) public boolean setDefaultSoundProfile(@Nullable String id) { try { - return mService.setDefaultSoundProfile(id, mUserId); + return mService.setDefaultSoundProfile(id, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -450,7 +485,7 @@ public final class MediaQualityManager { /** * Gets all package names whose sound profiles are available. * - * @see #getSoundProfilesByPackage(String) + * @see #getSoundProfilesByPackage(String, boolean) * * @hide */ @@ -459,7 +494,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) public List<String> getSoundProfilePackageNames() { try { - return mService.getSoundProfilePackageNames(mUserId); + return mService.getSoundProfilePackageNames(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -471,10 +506,12 @@ public final class MediaQualityManager { * * <p>If the profile is created successfully, * {@link SoundProfileCallback#onSoundProfileAdded(String, SoundProfile)} is invoked. + * + * @param sp the {@link SoundProfile} object to be created. */ public void createSoundProfile(@NonNull SoundProfile sp) { try { - mService.createSoundProfile(sp, mUserId); + mService.createSoundProfile(sp, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -483,10 +520,13 @@ public final class MediaQualityManager { /** * Updates an existing sound profile and store it in the system. + * + * @param profileId the id of the object to be updated. + * @param sp the {@link SoundProfile} object to be updated. */ public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) { try { - mService.updateSoundProfile(profileId, sp, mUserId); + mService.updateSoundProfile(profileId, sp, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -495,10 +535,12 @@ public final class MediaQualityManager { /** * Removes a sound profile from the system. + * + * @param profileId the id of the object to be removed. */ public void removeSoundProfile(@NonNull String profileId) { try { - mService.removeSoundProfile(profileId, mUserId); + mService.removeSoundProfile(profileId, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -510,7 +552,7 @@ public final class MediaQualityManager { @NonNull public List<ParamCapability> getParamCapabilities(@NonNull List<String> names) { try { - return mService.getParamCapabilities(names, mUserId); + return mService.getParamCapabilities(names, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -528,7 +570,7 @@ public final class MediaQualityManager { @NonNull public List<String> getPictureProfileAllowList() { try { - return mService.getPictureProfileAllowList(mUserId); + return mService.getPictureProfileAllowList(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -542,7 +584,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public void setPictureProfileAllowList(@NonNull List<String> packageNames) { try { - mService.setPictureProfileAllowList(packageNames, mUserId); + mService.setPictureProfileAllowList(packageNames, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -560,7 +602,7 @@ public final class MediaQualityManager { @NonNull public List<String> getSoundProfileAllowList() { try { - return mService.getSoundProfileAllowList(mUserId); + return mService.getSoundProfileAllowList(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -574,7 +616,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) public void setSoundProfileAllowList(@NonNull List<String> packageNames) { try { - mService.setSoundProfileAllowList(packageNames, mUserId); + mService.setSoundProfileAllowList(packageNames, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -586,7 +628,7 @@ public final class MediaQualityManager { */ public boolean isSupported() { try { - return mService.isSupported(mUserId); + return mService.isSupported(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -604,7 +646,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public void setAutoPictureQualityEnabled(boolean enabled) { try { - mService.setAutoPictureQualityEnabled(enabled, mUserId); + mService.setAutoPictureQualityEnabled(enabled, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -615,7 +657,7 @@ public final class MediaQualityManager { */ public boolean isAutoPictureQualityEnabled() { try { - return mService.isAutoPictureQualityEnabled(mUserId); + return mService.isAutoPictureQualityEnabled(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -632,7 +674,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public void setSuperResolutionEnabled(boolean enabled) { try { - mService.setSuperResolutionEnabled(enabled, mUserId); + mService.setSuperResolutionEnabled(enabled, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -643,7 +685,7 @@ public final class MediaQualityManager { */ public boolean isSuperResolutionEnabled() { try { - return mService.isSuperResolutionEnabled(mUserId); + return mService.isSuperResolutionEnabled(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -661,7 +703,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) public void setAutoSoundQualityEnabled(boolean enabled) { try { - mService.setAutoSoundQualityEnabled(enabled, mUserId); + mService.setAutoSoundQualityEnabled(enabled, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -672,7 +714,7 @@ public final class MediaQualityManager { */ public boolean isAutoSoundQualityEnabled() { try { - return mService.isAutoSoundQualityEnabled(mUserId); + return mService.isAutoSoundQualityEnabled(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -721,7 +763,7 @@ public final class MediaQualityManager { @NonNull AmbientBacklightSettings settings) { Preconditions.checkNotNull(settings); try { - mService.setAmbientBacklightSettings(settings, mUserId); + mService.setAmbientBacklightSettings(settings, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -732,7 +774,7 @@ public final class MediaQualityManager { */ public boolean isAmbientBacklightEnabled() { try { - return mService.isAmbientBacklightEnabled(mUserId); + return mService.isAmbientBacklightEnabled(mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -746,7 +788,7 @@ public final class MediaQualityManager { @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES) public void setAmbientBacklightEnabled(boolean enabled) { try { - mService.setAmbientBacklightEnabled(enabled, mUserId); + mService.setAmbientBacklightEnabled(enabled, mUserHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -803,11 +845,11 @@ public final class MediaQualityManager { }); } - public void postError(int error) { + public void postError(String profileId, int error) { mExecutor.execute(new Runnable() { @Override public void run() { - mCallback.onError(error); + mCallback.onError(profileId, error); } }); } @@ -863,11 +905,11 @@ public final class MediaQualityManager { }); } - public void postError(int error) { + public void postError(String profileId, int error) { mExecutor.execute(new Runnable() { @Override public void run() { - mCallback.onError(error); + mCallback.onError(profileId, error); } }); } @@ -933,9 +975,11 @@ public final class MediaQualityManager { /** * This is invoked when an issue has occurred. * + * @param profileId the profile ID related to the error. {@code null} if there is no + * associated profile. * @param errorCode the error code */ - public void onError(@PictureProfile.ErrorCode int errorCode) { + public void onError(@Nullable String profileId, @PictureProfile.ErrorCode int errorCode) { } /** @@ -988,9 +1032,11 @@ public final class MediaQualityManager { /** * This is invoked when an issue has occurred. * + * @param profileId the profile ID related to the error. {@code null} if there is no + * associated profile. * @param errorCode the error code */ - public void onError(@SoundProfile.ErrorCode int errorCode) { + public void onError(@Nullable String profileId, @SoundProfile.ErrorCode int errorCode) { } /** @@ -1016,4 +1062,86 @@ public final class MediaQualityManager { public void onAmbientBacklightEvent(@NonNull AmbientBacklightEvent event) { } } + + /** + * Listener used to monitor status of active pictures. + */ + public interface ActiveProcessingPictureListener { + /** + * Called when active pictures are changed. + * + * @param activeProcessingPictures contents currently undergoing picture processing. + */ + void onActiveProcessingPicturesChanged( + @NonNull List<ActiveProcessingPicture> activeProcessingPictures); + } + + /** + * Adds an active picture listener for the contents owner by the caller. + */ + public void addActiveProcessingPictureListener( + @CallbackExecutor @NonNull Executor executor, + @NonNull ActiveProcessingPictureListener listener) { + Preconditions.checkNotNull(listener); + Preconditions.checkNotNull(executor); + synchronized (mLock) { + mApListenerRecords.add( + new ActiveProcessingPictureListenerRecord(listener, executor, false)); + } + } + + /** + * Adds an active picture listener for all contents. + * + * @hide + */ + @SuppressLint("PairedRegistration") + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) + public void addGlobalActiveProcessingPictureListener( + @NonNull Executor executor, + @NonNull ActiveProcessingPictureListener listener) { + Preconditions.checkNotNull(listener); + Preconditions.checkNotNull(executor); + synchronized (mLock) { + mApListenerRecords.add( + new ActiveProcessingPictureListenerRecord(listener, executor, true)); + } + } + + + /** + * Removes an active picture listener for the contents. + */ + public void removeActiveProcessingPictureListener( + @NonNull ActiveProcessingPictureListener listener) { + Preconditions.checkNotNull(listener); + synchronized (mLock) { + for (Iterator<ActiveProcessingPictureListenerRecord> it = mApListenerRecords.iterator(); + it.hasNext(); ) { + ActiveProcessingPictureListenerRecord record = it.next(); + if (record.getListener() == listener) { + it.remove(); + break; + } + } + } + } + + private static final class ActiveProcessingPictureListenerRecord { + private final ActiveProcessingPictureListener mListener; + private final Executor mExecutor; + private final boolean mIsGlobal; + + ActiveProcessingPictureListenerRecord( + ActiveProcessingPictureListener listener, Executor executor, boolean isGlobal) { + mListener = listener; + mExecutor = executor; + mIsGlobal = isGlobal; + } + + public ActiveProcessingPictureListener getListener() { + return mListener; + } + } } diff --git a/media/java/android/media/quality/PictureProfileHandle.java b/media/java/android/media/quality/PictureProfileHandle.java index 714fd36d664a..d9d21932d09a 100644 --- a/media/java/android/media/quality/PictureProfileHandle.java +++ b/media/java/android/media/quality/PictureProfileHandle.java @@ -28,11 +28,14 @@ import android.os.Parcelable; * A picture profile represents a collection of parameters used to configure picture processing * to enhance the quality of graphic buffers. * + * @see PictureProfile.getHandle + * * @hide */ @SystemApi @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) public final class PictureProfileHandle implements Parcelable { + /** A handle that represents no picture processing configuration. */ public static final @NonNull PictureProfileHandle NONE = new PictureProfileHandle(0); private final long mId; @@ -42,7 +45,16 @@ public final class PictureProfileHandle implements Parcelable { mId = id; } - /** @hide */ + /** + * An ID that uniquely identifies the picture profile across the system. + * + * This ID can be used to construct an NDK PictureProfileHandle to be fed directly into + * IGraphicBufferProducer to couple a picture profile to a graphic buffer. + * + * Note: These IDs are generated randomly and are not stable across reboots. + * + * @hide + */ @SystemApi @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) public long getId() { diff --git a/native/android/dynamic_instrumentation_manager.cpp b/native/android/dynamic_instrumentation_manager.cpp index 532213611cf1..074973188c66 100644 --- a/native/android/dynamic_instrumentation_manager.cpp +++ b/native/android/dynamic_instrumentation_manager.cpp @@ -15,7 +15,9 @@ */ #define LOG_TAG "ADynamicInstrumentationManager" +#include <android-base/properties.h> #include <android/dynamic_instrumentation_manager.h> +#include <android/os/instrumentation/BnOffsetCallback.h> #include <android/os/instrumentation/ExecutableMethodFileOffsets.h> #include <android/os/instrumentation/IDynamicInstrumentationManager.h> #include <android/os/instrumentation/MethodDescriptor.h> @@ -23,7 +25,9 @@ #include <binder/Binder.h> #include <binder/IServiceManager.h> #include <utils/Log.h> +#include <utils/StrongPointer.h> +#include <future> #include <mutex> #include <optional> #include <string> @@ -31,6 +35,9 @@ namespace android::dynamicinstrumentationmanager { +using android::os::instrumentation::BnOffsetCallback; +using android::os::instrumentation::ExecutableMethodFileOffsets; + // Global instance of IDynamicInstrumentationManager, service is obtained only on first use. static std::mutex mLock; static sp<os::instrumentation::IDynamicInstrumentationManager> mService; @@ -131,6 +138,30 @@ void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy( delete instance; } +class ResultCallback : public BnOffsetCallback { +public: + ::android::binder::Status onResult( + const ::std::optional<ExecutableMethodFileOffsets>& offsets) override { + promise_.set_value(offsets); + return android::binder::Status::ok(); + } + + std::optional<ExecutableMethodFileOffsets> waitForResult() { + std::future<std::optional<ExecutableMethodFileOffsets>> futureResult = + promise_.get_future(); + auto futureStatus = futureResult.wait_for( + std::chrono::seconds(1 * android::base::HwTimeoutMultiplier())); + if (futureStatus == std::future_status::ready) { + return futureResult.get(); + } else { + return std::nullopt; + } + } + +private: + std::promise<std::optional<ExecutableMethodFileOffsets>> promise_; +}; + int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets( const ADynamicInstrumentationManager_TargetProcess* targetProcess, const ADynamicInstrumentationManager_MethodDescriptor* methodDescriptor, @@ -150,15 +181,15 @@ int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets( return INVALID_OPERATION; } - std::optional<android::os::instrumentation::ExecutableMethodFileOffsets> offsets; + android::sp<ResultCallback> resultCallback = android::sp<ResultCallback>::make(); binder_status_t result = service->getExecutableMethodFileOffsets(targetProcessParcel, methodDescriptorParcel, - &offsets) + resultCallback) .exceptionCode(); if (result != OK) { return result; } - + std::optional<ExecutableMethodFileOffsets> offsets = resultCallback->waitForResult(); if (offsets != std::nullopt) { auto* value = new ADynamicInstrumentationManager_ExecutableMethodFileOffsets(); value->containerPath = offsets->containerPath; @@ -170,4 +201,4 @@ int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets( } return result; -}
\ No newline at end of file +} diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index 1945d90568b3..9257901bcd1f 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -22,6 +22,7 @@ #include <aidl/android/hardware/power/SessionHint.h> #include <aidl/android/hardware/power/SessionMode.h> #include <aidl/android/hardware/power/SessionTag.h> +#include <aidl/android/hardware/power/SupportInfo.h> #include <aidl/android/hardware/power/WorkDuration.h> #include <aidl/android/hardware/power/WorkDurationFixedV1.h> #include <aidl/android/os/IHintManager.h> @@ -148,10 +149,36 @@ private: std::future<bool> mChannelCreationFinished; }; +class SupportInfoWrapper { +public: + SupportInfoWrapper(hal::SupportInfo& info); + bool isSessionModeSupported(hal::SessionMode mode); + bool isSessionHintSupported(hal::SessionHint hint); + +private: + template <class T> + bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) { + // extract the bit corresponding to the enum by shifting the bitfield + // over that much and cutting off any extra values + return (supportBitfield >> static_cast<int>(enumValue)) % 2; + } + hal::SupportInfo mSupportInfo; +}; + +class HintManagerClient : public IHintManager::BnHintManagerClient { +public: + // Currently a no-op that exists for FMQ init to call in the future + ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) { + return ndk::ScopedAStatus::ok(); + } +}; + struct APerformanceHintManager { public: static APerformanceHintManager* getInstance(); - APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos); + APerformanceHintManager(std::shared_ptr<IHintManager>& service, + IHintManager::HintManagerClientData&& clientData, + std::shared_ptr<HintManagerClient> callbackClient); APerformanceHintManager() = delete; ~APerformanceHintManager(); @@ -169,29 +196,21 @@ public: FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); void initJava(JNIEnv* _Nonnull env); - ndk::ScopedAIBinder_Weak x; template <class T> static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls, int numSurfaceControls, std::vector<T>& out); + ndk::SpAIBinder& getToken(); + SupportInfoWrapper& getSupportInfo(); private: - // Necessary to create an empty binder object - static void* tokenStubOnCreate(void*) { - return nullptr; - } - static void tokenStubOnDestroy(void*) {} - static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*, - AParcel*) { - return STATUS_OK; - } - static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager); std::shared_ptr<IHintManager> mHintManager; + std::shared_ptr<HintManagerClient> mCallbackClient; + IHintManager::HintManagerClientData mClientData; + SupportInfoWrapper mSupportInfoWrapper; ndk::SpAIBinder mToken; - const int64_t mPreferredRateNanos; - std::optional<int32_t> mMaxGraphicsPipelineThreadsCount; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; @@ -273,14 +292,27 @@ static FMQWrapper& getFMQ() { return APerformanceHintManager::getInstance()->getFMQWrapper(); } +// ===================================== SupportInfoWrapper implementation + +SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {} + +bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) { + return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints); +} + +bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) { + return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes); +} + // ===================================== APerformanceHintManager implementation APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager, - int64_t preferredRateNanos) - : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) { - static AIBinder_Class* tokenBinderClass = - AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy, - tokenStubOnTransact); - mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr)); + IHintManager::HintManagerClientData&& clientData, + std::shared_ptr<HintManagerClient> callbackClient) + : mHintManager(std::move(manager)), + mCallbackClient(callbackClient), + mClientData(clientData), + mSupportInfoWrapper(clientData.supportInfo), + mToken(callbackClient->asBinder()) { if (mFMQWrapper.isSupported()) { mFMQWrapper.setToken(mToken); mFMQWrapper.startChannel(mHintManager.get()); @@ -315,16 +347,17 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); return nullptr; } - int64_t preferredRateNanos = -1L; - ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos); + std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>(); + IHintManager::HintManagerClientData clientData; + ndk::ScopedAStatus ret = manager->registerClient(client, &clientData); if (!ret.isOk()) { - ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage()); + ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage()); return nullptr; } - if (preferredRateNanos <= 0) { - preferredRateNanos = -1L; + if (clientData.preferredRateNanos <= 0) { + clientData.preferredRateNanos = -1L; } - return new APerformanceHintManager(manager, preferredRateNanos); + return new APerformanceHintManager(manager, std::move(clientData), client); } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { @@ -389,7 +422,9 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; } - auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos, + + auto out = new APerformanceHintSession(mHintManager, std::move(session), + mClientData.preferredRateNanos, sessionCreationConfig->targetWorkDurationNanos, isJava, sessionConfig.id == -1 ? std::nullopt @@ -416,24 +451,11 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env } int64_t APerformanceHintManager::getPreferredRateNanos() const { - return mPreferredRateNanos; + return mClientData.preferredRateNanos; } int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() { - if (!mMaxGraphicsPipelineThreadsCount.has_value()) { - int32_t threadsCount = -1; - ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount); - if (!ret.isOk()) { - ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s", - __FUNCTION__, ret.getMessage()); - return -1; - } - if (threadsCount <= 0) { - threadsCount = -1; - } - mMaxGraphicsPipelineThreadsCount.emplace(threadsCount); - } - return mMaxGraphicsPipelineThreadsCount.value(); + return mClientData.maxGraphicsPipelineThreads; } FMQWrapper& APerformanceHintManager::getFMQWrapper() { @@ -450,6 +472,14 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) { mJavaInitialized = true; } +ndk::SpAIBinder& APerformanceHintManager::getToken() { + return mToken; +} + +SupportInfoWrapper& APerformanceHintManager::getSupportInfo() { + return mSupportInfoWrapper; +} + // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); @@ -1170,7 +1200,7 @@ int APerformanceHint_notifyWorkloadSpike(APerformanceHintSession* session, bool if (!useNewLoadHintBehavior()) { return ENOTSUP; } - return session->notifyWorkloadReset(cpu, gpu, debugName); + return session->notifyWorkloadSpike(cpu, gpu, debugName); } int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session, diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index c166e738ffb2..e3c10f63abb4 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -56,9 +56,6 @@ public: const SessionCreationConfig& creationConfig, hal::SessionConfig* config, std::shared_ptr<IHintSession>* _aidl_return), (override)); - MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override)); - MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return), - (override)); MOCK_METHOD(ScopedAStatus, setHintSessionThreads, (const std::shared_ptr<IHintSession>& hintSession, const ::std::vector<int32_t>& tids), @@ -84,6 +81,11 @@ public: MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); + MOCK_METHOD(ScopedAStatus, registerClient, + (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>& + clientDataIn, + ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return), + (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; @@ -125,10 +127,9 @@ public: APerformanceHintManager* createManager() { APerformanceHint_setUseFMQForTesting(mUsingFMQ); - ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_)) - .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); })); - ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_)) - .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); })); + ON_CALL(*mMockIHintManager, registerClient(_, _)) + .WillByDefault( + DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); })); return APerformanceHint_getManager(); } @@ -238,6 +239,20 @@ public: int kMockQueueSize = 20; bool mUsingFMQ = false; + IHintManager::HintManagerClientData mClientData{ + .powerHalVersion = 6, + .maxGraphicsPipelineThreads = 5, + .preferredRateNanos = 123L, + .supportInfo{ + .usesSessions = true, + .boosts = 0, + .modes = 0, + .sessionHints = -1, + .sessionModes = -1, + .sessionTags = -1, + }, + }; + int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; @@ -256,12 +271,6 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) { lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos; } -TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) { - APerformanceHintManager* manager = createManager(); - int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager); - EXPECT_EQ(123L, preferredUpdateRateNanos); -} - TEST_F(PerformanceHintTest, TestSession) { APerformanceHintManager* manager = createManager(); APerformanceHintSession* session = createSession(manager); 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/res/drawable/fill_dialog_dynamic_list_item_middle.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml index 781373dfbd0b..327f42209cdb 100644 --- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml +++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_middle.xml @@ -19,6 +19,6 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape> </inset>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml index f28c354b898d..992fe3341f26 100644 --- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml +++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml @@ -21,6 +21,6 @@ <shape android:shape="rectangle"> <corners android:topLeftRadius="4dp" android:topRightRadius="4dp" android:bottomLeftRadius="0dp" android:bottomRightRadius="0dp"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape> </inset>
\ No newline at end of file diff --git a/packages/CredentialManager/res/drawable/more_options_list_item.xml b/packages/CredentialManager/res/drawable/more_options_list_item.xml index 3f9d8157bfd2..991b3ff3c440 100644 --- a/packages/CredentialManager/res/drawable/more_options_list_item.xml +++ b/packages/CredentialManager/res/drawable/more_options_list_item.xml @@ -24,7 +24,7 @@ <shape> <corners android:topLeftRadius="0dp" android:topRightRadius="0dp" android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer"/> - <stroke android:color="?androidprv:attr/materialColorOutlineVariant" android:width="1dp"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainer"/> + <stroke android:color="@androidprv:color/materialColorOutlineVariant" android:width="1dp"/> </shape> </inset>
\ No newline at end of file diff --git a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml index 914987ac4650..6f04bd99877e 100644 --- a/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml +++ b/packages/CredentialManager/res/layout/credman_dropdown_bottom_sheet.xml @@ -35,7 +35,7 @@ android:layout_gravity="center" android:paddingStart="@dimen/autofill_view_left_padding" android:src="@drawable/more_horiz_24px" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:contentDescription="@string/more_options_content_description" android:background="@null"/> @@ -53,7 +53,7 @@ android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" style="@style/autofill.TextTitle"/> </LinearLayout> diff --git a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml index 3fc61545a713..d00a2295e43a 100644 --- a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml +++ b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml @@ -35,7 +35,7 @@ android:layout_gravity="center" android:layout_alignParentStart="true" android:paddingStart="@dimen/autofill_view_left_padding" - app:tint="?androidprv:attr/materialColorOnSurface" + app:tint="@androidprv:color/materialColorOnSurface" android:background="@null"/> <LinearLayout @@ -53,7 +53,7 @@ android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textDirection="locale" style="@style/autofill.TextTitle"/> @@ -61,7 +61,7 @@ android:id="@android:id/text2" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textDirection="locale" style="@style/autofill.TextSubtitle"/> diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml index 9d31b350b4a0..8d37d47cc9fe 100644 --- a/packages/CredentialManager/res/values/colors.xml +++ b/packages/CredentialManager/res/values/colors.xml @@ -19,8 +19,8 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <!-- These colors are used for Remote Views. --> - <color name="onSurface">?androidprv:attr/materialColorOnSurface</color> - <color name="onSurfaceVariant">?androidprv:attr/materialColorOnSurfaceVariant</color> - <color name="surfaceDim">?androidprv:attr/materialColorSurfaceDim</color> - <color name="surfaceContainer">?androidprv:attr/materialColorSurfaceContainer</color> + <color name="onSurface">@androidprv:color/materialColorOnSurface</color> + <color name="onSurfaceVariant">@androidprv:color/materialColorOnSurfaceVariant</color> + <color name="surfaceDim">@androidprv:color/materialColorSurfaceDim</color> + <color name="surfaceContainer">@androidprv:color/materialColorSurfaceContainer</color> </resources>
\ No newline at end of file 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/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/BundleUtil.java b/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/BundleUtil.java index 53ef9e889997..2626cc880e09 100644 --- a/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/BundleUtil.java +++ b/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/BundleUtil.java @@ -21,6 +21,7 @@ import static android.system.OsConstants.O_ACCMODE; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.PROT_READ; +import android.annotation.SuppressLint; import android.app.ondeviceintelligence.IResponseCallback; import android.app.ondeviceintelligence.IStreamingResponseCallback; import android.app.ondeviceintelligence.ITokenInfoCallback; @@ -328,6 +329,7 @@ public class BundleUtil { (value instanceof Boolean) || (value instanceof boolean[]); } + @SuppressLint("NewApi") private static void ensureValidBundle(Bundle bundle) { if (bundle == null) { throw new IllegalArgumentException("Request passed is expected to be non-null"); diff --git a/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java index 607ec1c71094..9ae0f03b7f60 100644 --- a/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java +++ b/packages/NeuralNetworks/service/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java @@ -16,8 +16,6 @@ package com.android.server.ondeviceintelligence; -import static android.app.ondeviceintelligence.flags.Flags.enableOnDeviceIntelligenceModule; - import static android.app.ondeviceintelligence.OnDeviceIntelligenceManager.ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS; import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.DEVICE_CONFIG_UPDATE_BUNDLE_KEY; import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BROADCAST_INTENT; @@ -180,10 +178,8 @@ public class OnDeviceIntelligenceManagerService extends SystemService { publishBinderService( Context.ON_DEVICE_INTELLIGENCE_SERVICE, getOnDeviceIntelligenceManagerService(), /* allowIsolated = */ true); - if (enableOnDeviceIntelligenceModule()) { - LocalManagerRegistry.addManager(OnDeviceIntelligenceManagerLocal.class, + LocalManagerRegistry.addManager(OnDeviceIntelligenceManagerLocal.class, this::getRemoteInferenceServiceUid); - } } @Override @@ -198,20 +194,6 @@ public class OnDeviceIntelligenceManagerService extends SystemService { } } - @Override - public void onUserUnlocked(@NonNull TargetUser user) { - Slog.d(TAG, "onUserUnlocked: " + user.getUserHandle()); - //connect to remote services(if available) during boot. - if (user.getUserHandle().equals(UserHandle.SYSTEM)) { - try { - ensureRemoteInferenceServiceInitialized(/* throwServiceIfInvalid */ false); - ensureRemoteIntelligenceServiceInitialized(/* throwServiceIfInvalid */ false); - } catch (Exception e) { - Slog.w(TAG, "Couldn't pre-start remote ondeviceintelligence services.", e); - } - } - } - private void onDeviceConfigChange(@NonNull Set<String> keys) { if (keys.contains(KEY_SERVICE_ENABLED)) { mIsServiceEnabled = isServiceEnabled(); diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING index 50db5018d44e..50331014f926 100644 --- a/packages/PackageInstaller/TEST_MAPPING +++ b/packages/PackageInstaller/TEST_MAPPING @@ -45,6 +45,17 @@ ] }, { + "name": "CtsPackageInstallerCUJUpdateOwnerShipTestCases", + "options":[ + { + "exclude-annotation":"androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation":"org.junit.Ignore" + } + ] + }, + { "name": "CtsPackageInstallerCUJUpdateSelfTestCases", "options":[ { diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml index 8d6f0da4262f..fdc59754df95 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml @@ -20,7 +20,7 @@ xmlns:tools="http://schemas.android.com/tools" tools:targetApi="28" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <corners android:topLeftRadius="?android:attr/dialogCornerRadius" android:topRightRadius="0dp" diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml index 307277264ff6..405c45272792 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml @@ -20,7 +20,7 @@ xmlns:tools="http://schemas.android.com/tools" tools:targetApi="28" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <corners android:topLeftRadius="0dp" android:topRightRadius="?android:attr/dialogCornerRadius" diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml index f1790f9ba351..187e612d11c4 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml @@ -20,7 +20,7 @@ xmlns:tools="http://schemas.android.com/tools" tools:targetApi="28" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <corners android:radius="?android:attr/dialogCornerRadius" /> diff --git a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml index d56c8434824f..0182b4c650a1 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml @@ -18,7 +18,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <corners android:radius="0dp" /> diff --git a/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml b/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml index cc948a670382..fd8cecb8536e 100644 --- a/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml +++ b/packages/SettingsLib/ActionButtonsPreference/res/values-v35/styles_expressive.xml @@ -22,12 +22,13 @@ <item name="iconGravity">textTop</item> </style> - <style name="SettingsLibActionButton.Expressive.Label" parent="SettingsLibTextAppearance.Emphasized.Title.Small"> + <style name="SettingsLibActionButton.Expressive.Label" parent=""> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:minWidth">@dimen/settingslib_expressive_space_small3</item> <item name="android:minHeight">@dimen/settingslib_expressive_space_small3</item> - <item name="android:textColor">@color/settingslib_materialColorOnSurface</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleSmall.Emphasized</item> + <item name="android:textColor">@color/settingslib_text_color_primary</item> <item name="android:layout_gravity">center</item> </style> diff --git a/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml b/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml index 716ed412eb5c..9018baca79e7 100644 --- a/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml +++ b/packages/SettingsLib/CardPreference/res/layout/settingslib_expressive_preference_card.xml @@ -40,7 +40,6 @@ <ImageView android:id="@android:id/icon" - android:src="@drawable/settingslib_arrow_drop_down" android:layout_width="@dimen/settingslib_expressive_space_medium3" android:layout_height="@dimen/settingslib_expressive_space_medium3" android:scaleType="centerInside"/> @@ -60,16 +59,12 @@ android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hyphenationFrequency="normalFast" - android:lineBreakWordStyle="phrase" android:textAppearance="@style/TextAppearance.CardTitle.SettingsLib"/> <TextView android:id="@android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hyphenationFrequency="normalFast" - android:lineBreakWordStyle="phrase" android:textAppearance="@style/TextAppearance.CardSummary.SettingsLib"/> </LinearLayout> diff --git a/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml b/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml index 4cbdea52d439..287b13fa0d50 100644 --- a/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml +++ b/packages/SettingsLib/CardPreference/res/values/styles_expressive.xml @@ -17,14 +17,12 @@ <resources> <style name="TextAppearance.CardTitle.SettingsLib" - parent="@style/TextAppearance.PreferenceTitle.SettingsLib"> + parent="@style/TextAppearance.SettingsLib.TitleMedium.Emphasized"> <item name="android:textColor">@color/settingslib_materialColorOnPrimary</item> - <item name="android:textSize">20sp</item> </style> <style name="TextAppearance.CardSummary.SettingsLib" - parent="@style/TextAppearance.PreferenceSummary.SettingsLib"> + parent="@style/TextAppearance.SettingsLib.LabelMedium"> <item name="android:textColor">@color/settingslib_materialColorOnSecondary</item> - <item name="android:textSize">14sp</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/drawable-v35/settingslib_expressive_icon_back.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/drawable-v35/settingslib_expressive_icon_back.xml index ccbe20e1c61f..9986a60250fe 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/drawable-v35/settingslib_expressive_icon_back.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/drawable-v35/settingslib_expressive_icon_back.xml @@ -17,12 +17,9 @@ <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item - android:start="16dp" - android:end="16dp" - android:top="4dp" - android:bottom="4dp"> + android:start="16dp"> <shape> - <size android:width="32dp" android:height="40dp" /> + <size android:width="40dp" android:height="40dp" /> <solid android:color="@color/settingslib_materialColorSurfaceContainerHighest" /> <corners android:radius="100dp" /> @@ -30,23 +27,21 @@ </item> <item - android:width="24dp" - android:height="24dp" + android:width="16dp" + android:height="16dp" android:gravity="center" android:start="16dp" - android:end="16dp" - android:top="4dp" - android:bottom="4dp"> +> <vector - android:width="24dp" - android:height="24dp" - android:viewportWidth="960" - android:viewportHeight="960" + android:width="16dp" + android:height="16dp" + android:viewportWidth="16" + android:viewportHeight="16" android:tint="@color/settingslib_materialColorOnSurfaceVariant" android:autoMirrored="true"> <path android:fillColor="@android:color/white" - android:pathData="M313,520L537,744L480,800L160,480L480,160L537,216L313,440L800,440L800,520L313,520Z"/> + android:pathData="M3.626,9L8.526,13.9C8.726,14.1 8.817,14.333 8.801,14.6C8.801,14.867 8.701,15.1 8.501,15.3C8.301,15.483 8.067,15.583 7.801,15.6C7.534,15.6 7.301,15.5 7.101,15.3L0.501,8.7C0.401,8.6 0.326,8.492 0.276,8.375C0.242,8.258 0.226,8.133 0.226,8C0.226,7.867 0.242,7.742 0.276,7.625C0.326,7.508 0.401,7.4 0.501,7.3L7.101,0.7C7.284,0.517 7.509,0.425 7.776,0.425C8.059,0.425 8.301,0.517 8.501,0.7C8.701,0.9 8.801,1.142 8.801,1.425C8.801,1.692 8.701,1.925 8.501,2.125L3.626,7H14.801C15.084,7 15.317,7.1 15.501,7.3C15.701,7.483 15.801,7.717 15.801,8C15.801,8.283 15.701,8.525 15.501,8.725C15.317,8.908 15.084,9 14.801,9H3.626Z"/> </vector> </item> </layer-list>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml index e68253e2200d..fadcf7ba8699 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml @@ -18,7 +18,7 @@ <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight"> <item name="elevationOverlayEnabled">true</item> <item name="elevationOverlayColor">?attr/colorPrimary</item> - <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item> + <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item> <item name="colorAccent">@color/settingslib_materialColorPrimaryFixed</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/styles_expressive.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/styles_expressive.xml index d58c2c2eeb23..37a78101cc4e 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/styles_expressive.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/styles_expressive.xml @@ -33,12 +33,12 @@ <item name="contentScrim">@color/settingslib_materialColorSurfaceContainer</item> </style> - <style name="SettingsLibCollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <style name="SettingsLibCollapsingToolbarTitle.Collapsed" parent="@style/TextAppearance.SettingsLib.TitleLarge.Emphasized"> <!--set dp because we don't want size adjust when font size change--> - <item name="android:textSize">20dp</item> + <item name="android:textSize">22dp</item> </style> - <style name="SettingsLibCollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed"> + <style name="SettingsLibCollapsingToolbarTitle.Expanded" parent="@style/TextAppearance.SettingsLib.DisplaySmall.Emphasized"> <item name="android:textSize">36dp</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml index f7c9aac68629..7c9d1a47b7ef 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml @@ -18,7 +18,7 @@ <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight"> <item name="elevationOverlayEnabled">true</item> <item name="elevationOverlayColor">?attr/colorPrimary</item> - <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item> + <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item> <item name="colorAccent">@color/settingslib_materialColorPrimary</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt index 5f1f8df02bbc..472ffa9289a7 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt @@ -47,6 +47,37 @@ interface KeyValueStore : KeyedObservable<String> { * @param value value to set, null means remove */ fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) + + /** Gets the boolean value of given key. */ + fun getBoolean(key: String): Boolean? = getValue(key, Boolean::class.javaObjectType) + + /** Sets boolean value for given key, null value means delete the key from data store. */ + fun setBoolean(key: String, value: Boolean?) = + setValue(key, Boolean::class.javaObjectType, value) + + /** Gets the float value of given key. */ + fun getFloat(key: String): Float? = getValue(key, Float::class.javaObjectType) + + /** Sets float value for given key, null value means delete the key from data store. */ + fun setFloat(key: String, value: Float?) = setValue(key, Float::class.javaObjectType, value) + + /** Gets the int value of given key. */ + fun getInt(key: String): Int? = getValue(key, Int::class.javaObjectType) + + /** Sets int value for given key, null value means delete the key from data store. */ + fun setInt(key: String, value: Int?) = setValue(key, Int::class.javaObjectType, value) + + /** Gets the long value of given key. */ + fun getLong(key: String): Long? = getValue(key, Long::class.javaObjectType) + + /** Sets long value for given key, null value means delete the key from data store. */ + fun setLong(key: String, value: Long?) = setValue(key, Long::class.javaObjectType, value) + + /** Gets the string value of given key. */ + fun getString(key: String): String? = getValue(key, String::class.javaObjectType) + + /** Sets string value for given key, null value means delete the key from data store. */ + fun setString(key: String, value: String?) = setValue(key, String::class.javaObjectType, value) } /** [SharedPreferences] based [KeyValueStore]. */ diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt index d6e7a896eb63..3f1a499807dd 100644 --- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt +++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt @@ -50,37 +50,6 @@ abstract class SettingsStore(protected val contentResolver: ContentResolver) : contentResolver.unregisterContentObserver(contentObserver) } - /** Gets the boolean value of given key. */ - fun getBoolean(key: String): Boolean? = getValue(key, Boolean::class.javaObjectType) - - /** Sets boolean value for given key, null value means delete the key from data store. */ - fun setBoolean(key: String, value: Boolean?) = - setValue(key, Boolean::class.javaObjectType, value) - - /** Gets the float value of given key. */ - fun getFloat(key: String): Float? = getValue(key, Float::class.javaObjectType) - - /** Sets float value for given key, null value means delete the key from data store. */ - fun setFloat(key: String, value: Float?) = setValue(key, Float::class.javaObjectType, value) - - /** Gets the int value of given key. */ - fun getInt(key: String): Int? = getValue(key, Int::class.javaObjectType) - - /** Sets int value for given key, null value means delete the key from data store. */ - fun setInt(key: String, value: Int?) = setValue(key, Int::class.javaObjectType, value) - - /** Gets the long value of given key. */ - fun getLong(key: String): Long? = getValue(key, Long::class.javaObjectType) - - /** Sets long value for given key, null value means delete the key from data store. */ - fun setLong(key: String, value: Long?) = setValue(key, Long::class.javaObjectType, value) - - /** Gets the string value of given key. */ - fun getString(key: String): String? = getValue(key, String::class.javaObjectType) - - /** Sets string value for given key, null value means delete the key from data store. */ - fun setString(key: String, value: String?) = setValue(key, String::class.javaObjectType, value) - /** Tag for logging. */ abstract val tag: String } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt index a768b5edb395..606710e6f356 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt @@ -55,9 +55,9 @@ import com.android.settingslib.metadata.RangeValue import com.android.settingslib.metadata.ReadWritePermit import com.android.settingslib.preference.PreferenceScreenFactory import com.android.settingslib.preference.PreferenceScreenProvider +import java.util.Locale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.Locale private const val TAG = "PreferenceGraphBuilder" @@ -399,15 +399,11 @@ fun PreferenceMetadata.toProto( value = preferenceValueProto { when (metadata) { is BooleanValue -> - metadata - .storage(context) - .getValue(metadata.key, Boolean::class.javaObjectType) - ?.let { booleanValue = it } + metadata.storage(context).getBoolean(metadata.key)?.let { + booleanValue = it + } is RangeValue -> { - metadata - .storage(context) - .getValue(metadata.key, Int::class.javaObjectType) - ?.let { intValue = it } + metadata.storage(context).getInt(metadata.key)?.let { intValue = it } } else -> {} } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt index 7cfce0d85cd4..56b169370e47 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt @@ -146,7 +146,7 @@ class PreferenceSetterApiHandler( val booleanValue = value.booleanValue val resultCode = metadata.checkWritePermit(booleanValue) if (resultCode != PreferenceSetterResult.OK) return resultCode - storage.setValue(key, Boolean::class.javaObjectType, booleanValue) + storage.setBoolean(key, booleanValue) return PreferenceSetterResult.OK } else if (value.hasIntValue()) { val intValue = value.intValue @@ -155,7 +155,7 @@ class PreferenceSetterApiHandler( if (metadata is RangeValue && !metadata.isValidValue(application, intValue)) { return PreferenceSetterResult.INVALID_REQUEST } - storage.setValue(key, Int::class.javaObjectType, intValue) + storage.setInt(key, intValue) return PreferenceSetterResult.OK } } catch (e: Exception) { diff --git a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml index 2edc001ccc3f..43cf6aa09109 100644 --- a/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml +++ b/packages/SettingsLib/IntroPreference/res/layout/settingslib_expressive_preference_intro.xml @@ -26,7 +26,6 @@ <ImageView android:id="@android:id/icon" - android:src="@drawable/settingslib_arrow_drop_down" style="@style/SettingsLibEntityHeaderIcon"/> <TextView diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java index 106802e9d1d1..73728bcd1ff7 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java @@ -32,6 +32,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.android.settingslib.widget.mainswitch.R; @@ -42,7 +43,7 @@ import java.util.List; /** * MainSwitchBar is a View with a customized Switch. * This component is used as the main switch of the page - * to enable or disable the prefereces on the page. + * to enable or disable the preferences on the page. */ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListener { @@ -58,6 +59,8 @@ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListen protected CompoundButton mSwitch; private final View mFrameView; + private @Nullable PreChangeListener mPreChangeListener; + public MainSwitchBar(Context context) { this(context, null); } @@ -138,10 +141,20 @@ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListen @Override public boolean performClick() { - mSwitch.performClick(); + if (callPreChangeListener()) { + mSwitch.performClick(); + } return super.performClick(); } + protected boolean callPreChangeListener() { + return mPreChangeListener == null || mPreChangeListener.preChange(!mSwitch.isChecked()); + } + + public void setPreChangeListener(@Nullable PreChangeListener preChangeListener) { + mPreChangeListener = preChangeListener; + } + /** * Update the switch status */ @@ -271,7 +284,7 @@ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListen } } - static class SavedState extends BaseSavedState { + public static class SavedState extends BaseSavedState { boolean mChecked; boolean mVisible; @@ -341,4 +354,16 @@ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListen requestLayout(); } + + /** + * Listener callback before switch is toggled. + */ + public interface PreChangeListener { + /** + * Returns if the new value can be set. + * + * When false is return, the switch toggle is not triggered at all. + */ + boolean preChange(boolean isCheck); + } } diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt index 6e86fa7312cf..c1edbdc20361 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceMetadata.kt @@ -107,20 +107,11 @@ interface PreferenceMetadata { * * UI framework normally does not allow user to interact with the preference widget when it is * disabled. - * - * [dependencyOfEnabledState] is provided to support dependency, the [shouldDisableDependents] - * value of dependent preference is used to decide enabled state. */ - fun isEnabled(context: Context): Boolean { - val dependency = dependencyOfEnabledState(context) ?: return true - return !dependency.shouldDisableDependents(context) - } - - /** Returns the key of depended preference to decide the enabled state. */ - fun dependencyOfEnabledState(context: Context): PreferenceMetadata? = null + fun isEnabled(context: Context): Boolean = true - /** Returns whether this preference's dependents should be disabled. */ - fun shouldDisableDependents(context: Context): Boolean = !isEnabled(context) + /** Returns the keys of depended preferences. */ + fun dependencies(context: Context): Array<String> = arrayOf() /** Returns if the preference is persistent in datastore. */ fun isPersistent(context: Context): Boolean = this is PersistentPreference<*> @@ -174,13 +165,11 @@ interface PreferenceMetadata { } /** Metadata of preference group. */ -@AnyThread -interface PreferenceGroup : PreferenceMetadata +@AnyThread interface PreferenceGroup : PreferenceMetadata /** Metadata of preference category. */ @AnyThread -open class PreferenceCategory(override val key: String, override val title: Int) : - PreferenceGroup +open class PreferenceCategory(override val key: String, override val title: Int) : PreferenceGroup /** Metadata of preference screen. */ @AnyThread diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt index 6704ecc93891..3dd15946d415 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt @@ -21,6 +21,7 @@ import android.content.ContextWrapper import android.content.Intent import android.os.Bundle import androidx.lifecycle.LifecycleCoroutineScope +import com.android.settingslib.datastore.KeyValueStore import kotlinx.coroutines.CoroutineScope /** @@ -157,6 +158,9 @@ abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(con */ abstract fun <T : Any> requirePreference(key: String): T + /** Returns the [KeyValueStore] attached to the preference of given key *on the same screen*. */ + abstract fun getKeyValueStore(key: String): KeyValueStore? + /** Notifies that preference state of given key is changed and updates preference widget UI. */ abstract fun notifyPreferenceChange(key: String) diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt index b64f5dc49b4b..87bd261bf4bd 100644 --- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt +++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceTypes.kt @@ -16,19 +16,10 @@ package com.android.settingslib.metadata -import android.content.Context import androidx.annotation.StringRes -/** - * Common base class for preferences that have two selectable states, save a boolean value, and may - * have dependent preferences that are enabled/disabled based on the current state. - */ -interface TwoStatePreference : PreferenceMetadata, PersistentPreference<Boolean>, BooleanValue { - - override fun shouldDisableDependents(context: Context) = - storage(context).getValue(key, Boolean::class.javaObjectType) != true || - super.shouldDisableDependents(context) -} +/** Common base class for preferences that have two selectable states and save a boolean value. */ +interface TwoStatePreference : PreferenceMetadata, PersistentPreference<Boolean>, BooleanValue /** A preference that provides a two-state toggleable option. */ open class SwitchPreference @@ -42,7 +33,4 @@ constructor( /** A preference that provides a two-state toggleable option that can be used as a main switch. */ open class MainSwitchPreference @JvmOverloads -constructor( - override val key: String, - @StringRes override val title: Int = 0, -) : TwoStatePreference
\ No newline at end of file +constructor(override val key: String, @StringRes override val title: Int = 0) : TwoStatePreference diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt index 7601b9a31041..f0f854aac79b 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceDataStoreAdapter.kt @@ -23,38 +23,31 @@ import com.android.settingslib.datastore.KeyValueStore class PreferenceDataStoreAdapter(val keyValueStore: KeyValueStore) : PreferenceDataStore() { override fun getBoolean(key: String, defValue: Boolean): Boolean = - keyValueStore.getValue(key, Boolean::class.javaObjectType) ?: defValue + keyValueStore.getBoolean(key) ?: defValue override fun getFloat(key: String, defValue: Float): Float = - keyValueStore.getValue(key, Float::class.javaObjectType) ?: defValue + keyValueStore.getFloat(key) ?: defValue - override fun getInt(key: String, defValue: Int): Int = - keyValueStore.getValue(key, Int::class.javaObjectType) ?: defValue + override fun getInt(key: String, defValue: Int): Int = keyValueStore.getInt(key) ?: defValue - override fun getLong(key: String, defValue: Long): Long = - keyValueStore.getValue(key, Long::class.javaObjectType) ?: defValue + override fun getLong(key: String, defValue: Long): Long = keyValueStore.getLong(key) ?: defValue override fun getString(key: String, defValue: String?): String? = - keyValueStore.getValue(key, String::class.javaObjectType) ?: defValue + keyValueStore.getString(key) ?: defValue @Suppress("UNCHECKED_CAST") override fun getStringSet(key: String, defValues: Set<String>?): Set<String>? = (keyValueStore.getValue(key, Set::class.javaObjectType) as Set<String>?) ?: defValues - override fun putBoolean(key: String, value: Boolean) = - keyValueStore.setValue(key, Boolean::class.javaObjectType, value) + override fun putBoolean(key: String, value: Boolean) = keyValueStore.setBoolean(key, value) - override fun putFloat(key: String, value: Float) = - keyValueStore.setValue(key, Float::class.javaObjectType, value) + override fun putFloat(key: String, value: Float) = keyValueStore.setFloat(key, value) - override fun putInt(key: String, value: Int) = - keyValueStore.setValue(key, Int::class.javaObjectType, value) + override fun putInt(key: String, value: Int) = keyValueStore.setInt(key, value) - override fun putLong(key: String, value: Long) = - keyValueStore.setValue(key, Long::class.javaObjectType, value) + override fun putLong(key: String, value: Long) = keyValueStore.setLong(key, value) - override fun putString(key: String, value: String?) = - keyValueStore.setValue(key, String::class.javaObjectType, value) + override fun putString(key: String, value: String?) = keyValueStore.setString(key, value) override fun putStringSet(key: String, values: Set<String>?) = keyValueStore.setValue(key, Set::class.javaObjectType, values) diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt index 6fc9357e9332..a9e20f284a61 100644 --- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt +++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt @@ -67,6 +67,11 @@ class PreferenceScreenBindingHelper( override fun <T : Any> requirePreference(key: String) = findPreference<T>(key)!! + override fun getKeyValueStore(key: String) = + (findPreference<Preference>(key)?.preferenceDataStore + as? PreferenceDataStoreAdapter) + ?.keyValueStore + override fun notifyPreferenceChange(key: String) = notifyChange(key, CHANGE_REASON_STATE) @@ -92,14 +97,14 @@ class PreferenceScreenBindingHelper( val preferencesBuilder = ImmutableMap.builder<String, PreferenceHierarchyNode>() val dependenciesBuilder = ImmutableMultimap.builder<String, String>() val lifecycleAwarePreferences = mutableListOf<PreferenceLifecycleProvider>() - fun PreferenceMetadata.addDependency(dependency: PreferenceMetadata) { - dependenciesBuilder.put(key, dependency.key) - } fun PreferenceHierarchyNode.addNode() { metadata.let { - preferencesBuilder.put(it.key, this) - it.dependencyOfEnabledState(context)?.addDependency(it) + val key = it.key + preferencesBuilder.put(key, this) + for (dependency in it.dependencies(context)) { + dependenciesBuilder.put(dependency, key) + } if (it is PreferenceLifecycleProvider) lifecycleAwarePreferences.add(it) } } diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant12.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant12.xml new file mode 100644 index 000000000000..f125425d1ec9 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant12.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="12"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant17.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant17.xml new file mode 100644 index 000000000000..36a781954e42 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant17.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="17"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant22.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant22.xml new file mode 100644 index 000000000000..0ef31d014aa2 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant22.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="22"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant24.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant24.xml new file mode 100644 index 000000000000..6797f82e4250 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant24.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="24"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant4.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant4.xml new file mode 100644 index 000000000000..ff7df5543a40 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant4.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="4"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant6.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant6.xml new file mode 100644 index 000000000000..8da5dafea567 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant6.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="6"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant87.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant87.xml new file mode 100644 index 000000000000..227baeedd99e --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant87.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="87"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant92.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant92.xml new file mode 100644 index 000000000000..f4564381eb33 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant92.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="92"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant94.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant94.xml new file mode 100644 index 000000000000..bb4e03d64307 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant94.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="94"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant96.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant96.xml new file mode 100644 index 000000000000..949b1961099f --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant96.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="96"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant98.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant98.xml new file mode 100644 index 000000000000..7e5ee241ffbd --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_neutral_variant98.xml @@ -0,0 +1,20 @@ +<?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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral2_600" android:lStar="98"/> +</selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_check.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_check.xml index 309dbdf1ea96..309dbdf1ea96 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_check.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_check.xml diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_close.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_close.xml index e6df8a416922..e6df8a416922 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_icon_close.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_icon_close.xml diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_switch_thumb_icon.xml b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_switch_thumb_icon.xml index 342729d7ee5a..342729d7ee5a 100644 --- a/packages/SettingsLib/SettingsTheme/res/drawable-v35/settingslib_expressive_switch_thumb_icon.xml +++ b/packages/SettingsLib/SettingsTheme/res/drawable/settingslib_expressive_switch_thumb_icon.xml diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml index ea7baa42a2c7..2261e58a961e 100644 --- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml +++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml @@ -40,7 +40,7 @@ android:longClickable="false" android:maxLines="10" android:ellipsize="end" - android:textAppearance="@style/TextAppearance.TopIntroText"/> + android:textAppearance="@style/TextAppearance.SettingsLib.BodyLarge"/> <com.android.settingslib.widget.LinkableTextView android:id="@+id/settingslib_expressive_learn_more" diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml b/packages/SettingsLib/SettingsTheme/res/layout/settingslib_expressive_preference_text_frame.xml index c837ff43e46b..db357f8ae13f 100644 --- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_preference_text_frame.xml +++ b/packages/SettingsLib/SettingsTheme/res/layout/settingslib_expressive_preference_text_frame.xml @@ -32,8 +32,6 @@ android:layout_gravity="start" android:textAlignment="viewStart" android:maxLines="2" - android:hyphenationFrequency="normalFast" - android:lineBreakWordStyle="phrase" android:textAppearance="?android:attr/textAppearanceListItem" android:ellipsize="marquee"/> @@ -47,7 +45,5 @@ android:textAlignment="viewStart" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" - android:maxLines="10" - android:hyphenationFrequency="normalFast" - android:lineBreakWordStyle="phrase"/> + android:maxLines="10"/> </RelativeLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml b/packages/SettingsLib/SettingsTheme/res/layout/settingslib_preference_category_no_title.xml index f69fcd270919..f69fcd270919 100644 --- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml +++ b/packages/SettingsLib/SettingsTheme/res/layout/settingslib_preference_category_no_title.xml diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml index 46ec62e7a5ef..8873116be306 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml @@ -58,4 +58,39 @@ <color name="settingslib_colorSurface">@color/settingslib_surface_dark</color> <color name="settingslib_list_divider_color">@android:color/system_neutral1_700</color> + + <color name="settingslib_materialColorPrimary">@android:color/system_accent1_200</color> + <color name="settingslib_materialColorOnPrimary">@android:color/system_accent1_800</color> + <color name="settingslib_materialColorPrimaryContainer">@android:color/system_accent1_700</color> + <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_accent1_100</color> + <color name="settingslib_materialColorPrimaryInverse">@android:color/system_accent1_600</color> + <color name="settingslib_materialColorSecondary">@android:color/system_accent2_200</color> + <color name="settingslib_materialColorOnSecondary">@android:color/system_accent2_800</color> + <color name="settingslib_materialColorSecondaryContainer">@android:color/system_accent2_700</color> + <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_accent2_100</color> + <color name="settingslib_materialColorTertiary">@android:color/system_accent3_200</color> + <color name="settingslib_materialColorOnTertiary">@android:color/system_accent3_800</color> + <color name="settingslib_materialColorTertiaryContainer">@android:color/system_accent3_700</color> + <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_accent3_100</color> + <color name="settingslib_materialColorError">@color/settingslib_error_200</color> + <color name="settingslib_materialColorOnError">@color/settingslib_error_800</color> + <color name="settingslib_materialColorErrorContainer">@color/settingslib_error_700</color> + <color name="settingslib_materialColorOnErrorContainer">@color/settingslib_error_100</color> + <color name="settingslib_materialColorOutline">@android:color/system_neutral2_400</color> + <color name="settingslib_materialColorOutlineVariant">@android:color/system_neutral2_700</color> + <color name="settingslib_materialColorBackground">@color/settingslib_neutral_variant6</color> + <color name="settingslib_materialColorOnBackground">@android:color/system_neutral1_100</color> + <color name="settingslib_materialColorSurface">@color/settingslib_neutral_variant6</color> + <color name="settingslib_materialColorOnSurface">@android:color/system_neutral1_100</color> + <color name="settingslib_materialColorSurfaceVariant">@android:color/system_neutral2_700</color> + <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_neutral2_200</color> + <color name="settingslib_materialColorSurfaceInverse">@android:color/system_neutral1_100</color> + <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_neutral1_800</color> + <color name="settingslib_materialColorSurfaceBright">@color/settingslib_neutral_variant24</color> + <color name="settingslib_materialColorSurfaceDim">@color/settingslib_neutral_variant6</color> + <color name="settingslib_materialColorSurfaceContainer">@color/settingslib_neutral_variant12</color> + <color name="settingslib_materialColorSurfaceContainerLowest">@color/settingslib_neutral_variant4</color> + <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_neutral2_900</color> + <color name="settingslib_materialColorSurfaceContainerHigh">@color/settingslib_neutral_variant17</color> + <color name="settingslib_materialColorSurfaceContainerHighest">@color/settingslib_neutral_variant22</color> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml index 8cfe54f44fe5..00a1f27c162a 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v34/colors.xml @@ -42,4 +42,39 @@ <color name="settingslib_text_color_primary_device_default">@android:color/system_on_surface_dark</color> <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurfaceVariant--> <color name="settingslib_text_color_secondary_device_default">@android:color/system_on_surface_variant_dark</color> + + <color name="settingslib_materialColorPrimary">@android:color/system_primary_dark</color> + <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_dark</color> + <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color> + <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color> + <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_light</color> + <color name="settingslib_materialColorSecondary">@android:color/system_secondary_dark</color> + <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_dark</color> + <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color> + <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_dark</color> + <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_dark</color> + <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_dark</color> + <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color> + <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_dark</color> + <color name="settingslib_materialColorError">@android:color/system_error_dark</color> + <color name="settingslib_materialColorOnError">@android:color/system_on_error_dark</color> + <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color> + <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color> + <color name="settingslib_materialColorOutline">@android:color/system_outline_dark</color> + <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_dark</color> + <color name="settingslib_materialColorBackground">@android:color/system_background_dark</color> + <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_dark</color> + <color name="settingslib_materialColorSurface">@android:color/system_surface_dark</color> + <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_dark</color> + <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color> + <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_dark</color> + <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_light</color> + <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_light</color> + <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_dark</color> + <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_dark</color> + <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_dark</color> + <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color> + <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_dark</color> + <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_dark</color> + <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_dark</color> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml index 84a3ed68af01..e31e80176625 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml @@ -46,37 +46,4 @@ <color name="settingslib_colorSurfaceHeader">@color/settingslib_materialColorSurfaceVariant</color> <color name="settingslib_text_color_preference_category_title">@color/settingslib_materialColorPrimary</color> - - <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_dark</color> - <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_dark</color> - <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_dark</color> - <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color> - <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color> - <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color> - <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_light</color> - <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color> - <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color> - <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_light</color> - <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_light</color> - <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color> - <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color> - <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color> - <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_dark</color> - <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_dark</color> - <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_dark</color> - <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_dark</color> - <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_dark</color> - <color name="settingslib_materialColorOnError">@android:color/system_on_error_dark</color> - <color name="settingslib_materialColorSurface">@android:color/system_surface_dark</color> - <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_dark</color> - <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_dark</color> - <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_dark</color> - <color name="settingslib_materialColorOutline">@android:color/system_outline_dark</color> - <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_dark</color> - <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_dark</color> - <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_dark</color> - <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_dark</color> - <color name="settingslib_materialColorPrimary">@android:color/system_primary_dark</color> - <color name="settingslib_materialColorSecondary">@android:color/system_secondary_dark</color> - <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_dark</color> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml new file mode 100644 index 000000000000..e57fe4f512fe --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values-night/colors.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <color name="settingslib_materialColorPrimary">#83D6C7</color> + <color name="settingslib_materialColorOnPrimary">#003730</color> + <color name="settingslib_materialColorPrimaryContainer">#005047</color> + <color name="settingslib_materialColorOnPrimaryContainer">#A1F1E2</color> + <color name="settingslib_materialColorPrimaryInverse">#A1F1E2</color> + <color name="settingslib_materialColorSecondary">#B1CCC6</color> + <color name="settingslib_materialColorOnSecondary">#1C342F</color> + <color name="settingslib_materialColorSecondaryContainer">#334C47</color> + <color name="settingslib_materialColorOnSecondaryContainer">#CCE8E2</color> + <color name="settingslib_materialColorTertiary">#ADCAE5</color> + <color name="settingslib_materialColorOnTertiary">#123349</color> + <color name="settingslib_materialColorTertiaryContainer">#2D4960</color> + <color name="settingslib_materialColorOnTertiaryContainer">#CEE7FF</color> + <color name="settingslib_materialColorError">#F2B8B5</color> + <color name="settingslib_materialColorOnError">#601410</color> + <color name="settingslib_materialColorErrorContainer">#8C1D18</color> + <color name="settingslib_materialColorOnErrorContainer">#F9DEDC</color> + <color name="settingslib_materialColorOutline">#919191</color> + <color name="settingslib_materialColorOutlineVariant">#474747</color> + <color name="settingslib_materialColorBackground">#131313</color> + <color name="settingslib_materialColorOnBackground">#E5E2E1</color> + <color name="settingslib_materialColorSurface">#131313</color> + <color name="settingslib_materialColorOnSurface">#E5E2E1</color> + <color name="settingslib_materialColorSurfaceVariant">#474747</color> + <color name="settingslib_materialColorOnSurfaceVariant">#C7C7C7</color> + <color name="settingslib_materialColorSurfaceInverse">#E5E2E1</color> + <color name="settingslib_materialColorOnSurfaceInverse">#303030</color> + <color name="settingslib_materialColorSurfaceBright">#393939</color> + <color name="settingslib_materialColorSurfaceDim">#131313</color> + <color name="settingslib_materialColorSurfaceContainer">#1F1F1F</color> + <color name="settingslib_materialColorSurfaceContainerLowest">#1B1B1B</color> + <color name="settingslib_materialColorSurfaceContainerLow">#0E0E0E</color> + <color name="settingslib_materialColorSurfaceContainerHigh">#2A2A2A</color> + <color name="settingslib_materialColorSurfaceContainerHighest">#343434</color> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml index fef92b792bec..e000423784c6 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml @@ -92,4 +92,51 @@ <color name="settingslib_spinner_dropdown_color">@android:color/system_neutral2_700</color> <color name="settingslib_list_divider_color">@android:color/system_neutral1_200</color> + + <color name="settingslib_materialColorPrimary">@android:color/system_accent1_600</color> + <color name="settingslib_materialColorOnPrimary">@android:color/system_accent1_0</color> + <color name="settingslib_materialColorPrimaryContainer">@android:color/system_accent1_100</color> + <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_accent1_900</color> + <color name="settingslib_materialColorPrimaryInverse">@android:color/system_accent1_200</color> + <color name="settingslib_materialColorPrimaryFixed">@android:color/system_accent1_100</color> + <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_accent1_200</color> + <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_accent1_900</color> + <color name="settingslib_materialColorOnPrimaryFixedVariant">@android:color/system_accent1_700</color> + <color name="settingslib_materialColorSecondary">@android:color/system_accent2_600</color> + <color name="settingslib_materialColorOnSecondary">@android:color/system_accent2_0</color> + <color name="settingslib_materialColorSecondaryContainer">@android:color/system_accent2_100</color> + <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_accent2_900</color> + <color name="settingslib_materialColorSecondaryFixed">@android:color/system_accent2_100</color> + <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_accent2_200</color> + <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_accent2_900</color> + <color name="settingslib_materialColorOnSecondaryFixedVariant">@android:color/system_accent2_700</color> + <color name="settingslib_materialColorTertiary">@android:color/system_accent3_600</color> + <color name="settingslib_materialColorOnTertiary">@android:color/system_accent3_0</color> + <color name="settingslib_materialColorTertiaryContainer">@android:color/system_accent3_100</color> + <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_accent3_900</color> + <color name="settingslib_materialColorTertiaryFixed">@android:color/system_accent3_100</color> + <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_accent3_200</color> + <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_accent3_900</color> + <color name="settingslib_materialColorOnTertiaryFixedVariant">@android:color/system_accent3_700</color> + <color name="settingslib_materialColorError">@color/settingslib_error_600</color> + <color name="settingslib_materialColorOnError">@android:color/white</color> + <color name="settingslib_materialColorErrorContainer">@color/settingslib_error_100</color> + <color name="settingslib_materialColorOnErrorContainer">@color/settingslib_error_900</color> + <color name="settingslib_materialColorOutline">@android:color/system_neutral2_500</color> + <color name="settingslib_materialColorOutlineVariant">@android:color/system_neutral2_200</color> + <color name="settingslib_materialColorBackground">@android:color/white</color> + <color name="settingslib_materialColorOnBackground">@android:color/system_neutral1_900</color> + <color name="settingslib_materialColorSurface">@color/settingslib_neutral_variant98</color> + <color name="settingslib_materialColorOnSurface">@android:color/system_neutral1_900</color> + <color name="settingslib_materialColorSurfaceVariant">@android:color/system_neutral2_100</color> + <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_neutral2_700</color> + <color name="settingslib_materialColorSurfaceInverse">@android:color/system_neutral1_800</color> + <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_neutral1_50</color> + <color name="settingslib_materialColorSurfaceBright">@color/settingslib_neutral_variant98</color> + <color name="settingslib_materialColorSurfaceDim">@color/settingslib_neutral_variant87</color> + <color name="settingslib_materialColorSurfaceContainer">@color/settingslib_neutral_variant94</color> + <color name="settingslib_materialColorSurfaceContainerLow">@color/settingslib_neutral_variant96</color> + <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_neutral2_0</color> + <color name="settingslib_materialColorSurfaceContainerHigh">@color/settingslib_neutral_variant92</color> + <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_neutral2_100</color> </resources> diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/config.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/config.xml index 4860ad361744..8993d0fc71f7 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/config.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/config.xml @@ -17,6 +17,4 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <bool name="settingslib_config_icon_space_reserved">false</bool> <bool name="settingslib_config_allow_divider">false</bool> - <!-- Name of a font family to use for headlines in SettingsLib. --> - <string name="settingslib_config_headlineFontFamily" translatable="false"></string> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml new file mode 100644 index 000000000000..9d3d70b366aa --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + <style name="SettingsLibButtonStyle.Expressive.Filled" + parent="@style/Widget.Material3.Button"> + <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">center</item> + <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> + <item name="android:backgroundTint">@color/settingslib_materialColorPrimary</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item> + <item name="android:textColor">@color/settingslib_materialColorOnPrimary</item> + <item name="iconGravity">textStart</item> + <item name="iconTint">@color/settingslib_materialColorOnPrimary</item> + <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Filled.Large"> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Filled.Extra" + parent="@style/SettingsLibButtonStyle.Expressive.Filled.Large"> + <item name="android:layout_width">match_parent</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Tonal" + parent="@style/Widget.Material3.Button.TonalButton"> + <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">center</item> + <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> + <item name="android:backgroundTint">@color/settingslib_materialColorSecondaryContainer</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item> + <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item> + <item name="iconGravity">textStart</item> + <item name="iconTint">@color/settingslib_materialColorOnSecondaryContainer</item> + <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Tonal.Large"> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Tonal.Extra" + parent="@style/SettingsLibButtonStyle.Expressive.Tonal.Large"> + <item name="android:layout_width">match_parent</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Outline" + parent="@style/Widget.Material3.Button.OutlinedButton.Icon"> + <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:gravity">center</item> + <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item> + <item name="android:textColor">@color/settingslib_materialColorPrimary</item> + <item name="iconTint">@color/settingslib_materialColorPrimary</item> + <item name="iconGravity">textStart</item> + <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> + <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="strokeColor">@color/settingslib_materialColorOutlineVariant</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Outline.Large"> + <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> + <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item> + </style> + + <style name="SettingsLibButtonStyle.Expressive.Outline.Extra" + parent="@style/SettingsLibButtonStyle.Expressive.Outline.Large"> + <item name="android:layout_width">match_parent</item> + </style> + + <style name="SettingslibTextButtonStyle.Expressive" + parent="@style/Widget.Material3.Button.TextButton.Icon"> + <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.BodyLarge.Emphasized</item> + <item name="android:textColor">@color/settingslib_materialColorOnSurface</item> + <item name="iconTint">@null</item> + <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="rippleColor">?android:attr/colorControlHighlight</item> + </style> + + <style name="SettingsLibCardStyle" parent=""> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_marginHorizontal">?android:attr/listPreferredItemPaddingStart</item> + <item name="android:layout_marginVertical">@dimen/settingslib_expressive_space_extrasmall4</item> + <item name="cardBackgroundColor">@color/settingslib_materialColorPrimary</item> + <item name="cardCornerRadius">@dimen/settingslib_expressive_radius_extralarge3</item> + <item name="cardElevation">0dp</item> + <item name="rippleColor">?android:attr/colorControlHighlight</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v33/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v33/styles_expressive.xml new file mode 100644 index 000000000000..74bf55a8a625 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values-v33/styles_expressive.xml @@ -0,0 +1,306 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources> + <style name="TextAppearance.SettingsLib.DisplayLarge" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">57sp</item> + <item name="android:letterSpacing">-0.00438596</item> + <item name="android:lineHeight">64sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplayMedium" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">45sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">52sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplaySmall" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">36sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">44sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.HeadlineLarge" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">32sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">40sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineMedium" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">28sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">36sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineSmall" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">24sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">32sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.TitleLarge" + parent="@android:style/TextAppearance.DeviceDefault.Headline"> + <item name="android:textSize">22sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">28sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleMedium" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight">24sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleSmall" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.LabelLarge" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelMedium" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.04166667</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelSmall" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">11sp</item> + <item name="android:letterSpacing">0.04545455</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.BodyLarge" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.03125</item> + <item name="android:lineHeight">24sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodyMedium" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.01785714</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodySmall" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.03333333</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.DisplayLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">57sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">64sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplayMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">45sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">52sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplaySmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">36sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">44sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.HeadlineLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">32sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">40sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">28sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">36sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">24sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">32sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.TitleLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">22sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight">28sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight">24sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.LabelLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.04166667</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">11sp</item> + <item name="android:letterSpacing">0.04545455</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.BodyLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight">24sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodyMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.01785714</item> + <item name="android:lineHeight">20sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodySmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.03333333</item> + <item name="android:lineHeight">16sp</item> + <item name="android:hyphenationFrequency">normalFast</item> + <item name="android:lineBreakWordStyle">phrase</item> + <item name="android:textAllCaps">false</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml index 185ac3e1fe73..60642e617a81 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v34/colors.xml @@ -43,4 +43,51 @@ <color name="settingslib_text_color_primary_device_default">@android:color/system_on_surface_light</color> <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurfaceVariant--> <color name="settingslib_text_color_secondary_device_default">@android:color/system_on_surface_variant_light</color> + + <color name="settingslib_materialColorPrimary">@android:color/system_primary_light</color> + <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_light</color> + <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_light</color> + <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_light</color> + <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_dark</color> + <color name="settingslib_materialColorPrimaryFixed">@android:color/system_primary_fixed</color> + <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color> + <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color> + <color name="settingslib_materialColorOnPrimaryFixedVariant">@android:color/system_on_primary_fixed_variant</color> + <color name="settingslib_materialColorSecondary">@android:color/system_secondary_light</color> + <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_light</color> + <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color> + <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_light</color> + <color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color> + <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color> + <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color> + <color name="settingslib_materialColorOnSecondaryFixedVariant">@android:color/system_on_secondary_fixed_variant</color> + <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_light</color> + <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_light</color> + <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color> + <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_light</color> + <color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color> + <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color> + <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color> + <color name="settingslib_materialColorOnTertiaryFixedVariant">@android:color/system_on_tertiary_fixed_variant</color> + <color name="settingslib_materialColorError">@android:color/system_error_light</color> + <color name="settingslib_materialColorOnError">@android:color/system_on_error_light</color> + <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color> + <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color> + <color name="settingslib_materialColorOutline">@android:color/system_outline_light</color> + <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_light</color> + <color name="settingslib_materialColorBackground">@android:color/system_background_light</color> + <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_light</color> + <color name="settingslib_materialColorSurface">@android:color/system_surface_light</color> + <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_light</color> + <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color> + <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_light</color> + <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_dark</color> + <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_dark</color> + <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_light</color> + <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_light</color> + <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_light</color> + <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_light</color> + <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_light</color> + <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_light</color> + <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_light</color> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml index 90c19e1aa676..b1b37b12c572 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml @@ -54,49 +54,4 @@ <color name="settingslib_spinner_title_color">@color/settingslib_materialColorOnPrimaryContainer</color> <!-- The text color of dropdown item title --> <color name="settingslib_spinner_dropdown_color">@color/settingslib_materialColorOnPrimaryContainer</color> - - <color name="settingslib_materialColorOnSecondaryFixedVariant">@android:color/system_on_secondary_fixed_variant</color> - <color name="settingslib_materialColorOnTertiaryFixedVariant">@android:color/system_on_tertiary_fixed_variant</color> - <color name="settingslib_materialColorSurfaceContainerLowest">@android:color/system_surface_container_lowest_light</color> - <color name="settingslib_materialColorOnPrimaryFixedVariant">@android:color/system_on_primary_fixed_variant</color> - <color name="settingslib_materialColorOnSecondaryContainer">@android:color/system_on_secondary_container_light</color> - <color name="settingslib_materialColorOnTertiaryContainer">@android:color/system_on_tertiary_container_light</color> - <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_light</color> - <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_light</color> - <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color> - <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color> - <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color> - <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_dark</color> - <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color> - <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color> - <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color> - <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color> - <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color> - <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color> - <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_dark</color> - <color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color> - <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_dark</color> - <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color> - <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color> - <color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color> - <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_light</color> - <color name="settingslib_materialColorOnBackground">@android:color/system_on_background_light</color> - <color name="settingslib_materialColorPrimaryFixed">@android:color/system_primary_fixed</color> - <color name="settingslib_materialColorOnSecondary">@android:color/system_on_secondary_light</color> - <color name="settingslib_materialColorOnTertiary">@android:color/system_on_tertiary_light</color> - <color name="settingslib_materialColorSurfaceDim">@android:color/system_surface_dim_light</color> - <color name="settingslib_materialColorSurfaceBright">@android:color/system_surface_bright_light</color> - <color name="settingslib_materialColorOnError">@android:color/system_on_error_light</color> - <color name="settingslib_materialColorSurface">@android:color/system_surface_light</color> - <color name="settingslib_materialColorSurfaceContainerHigh">@android:color/system_surface_container_high_light</color> - <color name="settingslib_materialColorSurfaceContainerHighest">@android:color/system_surface_container_highest_light</color> - <color name="settingslib_materialColorOnSurfaceVariant">@android:color/system_on_surface_variant_light</color> - <color name="settingslib_materialColorOutline">@android:color/system_outline_light</color> - <color name="settingslib_materialColorOutlineVariant">@android:color/system_outline_variant_light</color> - <color name="settingslib_materialColorOnPrimary">@android:color/system_on_primary_light</color> - <color name="settingslib_materialColorOnSurface">@android:color/system_on_surface_light</color> - <color name="settingslib_materialColorSurfaceContainer">@android:color/system_surface_container_light</color> - <color name="settingslib_materialColorPrimary">@android:color/system_primary_light</color> - <color name="settingslib_materialColorSecondary">@android:color/system_secondary_light</color> - <color name="settingslib_materialColorTertiary">@android:color/system_tertiary_light</color> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml index 05a1ceacdb65..1a085681864a 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v35/styles_expressive.xml @@ -16,150 +16,6 @@ --> <resources> - <style name="SettingsLibTextAppearance" parent="@android:style/TextAppearance.DeviceDefault"> - <!--item name="android:fontFamily"></item--> - <item name="android:hyphenationFrequency">normalFast</item> - <item name="android:lineBreakWordStyle">phrase</item> - </style> - - <style name="SettingsLibTextAppearance.Primary"> - <!--item name="android:fontFamily"></item--> - </style> - - <style name="SettingsLibTextAppearance.Primary.Display"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Primary.Display.Large"> - <item name="android:textSize">57sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Display.Medium"> - <item name="android:textSize">45sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Display.Small"> - <item name="android:textSize">36sp</item> - </style> - - <style name="SettingsLibTextAppearance.Primary.Headline"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Primary.Headline.Large"> - <item name="android:textSize">32sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Headline.Medium"> - <item name="android:textSize">28sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Headline.Small"> - <item name="android:textSize">24sp</item> - </style> - - <style name="SettingsLibTextAppearance.Primary.Title"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Primary.Title.Large"> - <item name="android:textSize">22sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Title.Medium"> - <item name="android:textSize">16sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Title.Small"> - <item name="android:textSize">14sp</item> - </style> - - <style name="SettingsLibTextAppearance.Primary.Label"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Primary.Label.Large"> - <item name="android:textSize">14sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Label.Medium"> - <item name="android:textSize">12sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Label.Small"> - <item name="android:textSize">11sp</item> - </style> - - <style name="SettingsLibTextAppearance.Primary.Body"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Primary.Body.Large"> - <item name="android:textSize">16sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Body.Medium"> - <item name="android:textSize">14sp</item> - </style> - <style name="SettingsLibTextAppearance.Primary.Body.Small"> - <item name="android:textSize">12sp</item> - </style> - - <style name="SettingsLibTextAppearance.Emphasized"> - <!--item name="android:fontFamily"></item--> - </style> - - <style name="SettingsLibTextAppearance.Emphasized.Display"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Display.Large"> - <item name="android:textSize">57sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Display.Medium"> - <item name="android:textSize">45sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Display.Small"> - <item name="android:textSize">36sp</item> - </style> - - <style name="SettingsLibTextAppearance.Emphasized.Headline"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Headline.Large"> - <item name="android:textSize">32sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Headline.Medium"> - <item name="android:textSize">28sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Headline.Small"> - <item name="android:textSize">24sp</item> - </style> - - <style name="SettingsLibTextAppearance.Emphasized.Title"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Title.Large"> - <item name="android:textSize">22sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Title.Medium"> - <item name="android:textSize">16sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Title.Small"> - <item name="android:textSize">14sp</item> - </style> - - <style name="SettingsLibTextAppearance.Emphasized.Label"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Label.Large"> - <item name="android:textSize">14sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Label.Medium"> - <item name="android:textSize">12sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Label.Small"> - <item name="android:textSize">11sp</item> - </style> - - <style name="SettingsLibTextAppearance.Emphasized.Body"> - <!--item name="android:fontFamily"></item--> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Body.Large"> - <item name="android:textSize">16sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Body.Medium"> - <item name="android:textSize">14sp</item> - </style> - <style name="SettingsLibTextAppearance.Emphasized.Body.Small"> - <item name="android:textSize">12sp</item> - </style> - <style name="SettingslibSwitchStyle.Expressive" parent=""> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> @@ -175,122 +31,6 @@ <item name="trackTint">@color/settingslib_expressive_color_main_switch_track</item> </style> - <style name="SettingsLibCardStyle" parent=""> - <item name="android:layout_width">match_parent</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:layout_marginHorizontal">?android:attr/listPreferredItemPaddingStart</item> - <item name="android:layout_marginVertical">@dimen/settingslib_expressive_space_extrasmall4</item> - <item name="cardBackgroundColor">@color/settingslib_materialColorPrimary</item> - <item name="cardCornerRadius">@dimen/settingslib_expressive_radius_extralarge3</item> - <item name="cardElevation">0dp</item> - <item name="rippleColor">?android:attr/colorControlHighlight</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Filled" - parent="@style/Widget.Material3.Button"> - <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:gravity">center</item> - <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> - <item name="android:backgroundTint">@color/settingslib_materialColorPrimary</item> - <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> - <item name="android:textColor">@color/settingslib_materialColorOnPrimary</item> - <item name="android:textSize">14sp</item> - <item name="iconGravity">textStart</item> - <item name="iconTint">@color/settingslib_materialColorOnPrimary</item> - <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Filled.Large"> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> - <item name="android:textSize">16sp</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Filled.Extra" - parent="@style/SettingsLibButtonStyle.Expressive.Filled.Large"> - <item name="android:layout_width">match_parent</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Tonal" - parent="@style/Widget.Material3.Button.TonalButton"> - <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:gravity">center</item> - <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> - <item name="android:backgroundTint">@color/settingslib_materialColorSecondaryContainer</item> - <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> - <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item> - <item name="android:textSize">14sp</item> - <item name="iconGravity">textStart</item> - <item name="iconTint">@color/settingslib_materialColorOnSecondaryContainer</item> - <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Tonal.Large"> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> - <item name="android:textSize">16sp</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Tonal.Extra" - parent="@style/SettingsLibButtonStyle.Expressive.Tonal.Large"> - <item name="android:layout_width">match_parent</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Outline" - parent="@style/Widget.Material3.Button.OutlinedButton.Icon"> - <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:gravity">center</item> - <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item> - <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> - <item name="android:textColor">@color/settingslib_materialColorPrimary</item> - <item name="android:textSize">14sp</item> - <item name="iconTint">@color/settingslib_materialColorPrimary</item> - <item name="iconGravity">textStart</item> - <item name="iconSize">@dimen/settingslib_expressive_space_small4</item> - <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item> - <item name="strokeColor">@color/settingslib_materialColorOutlineVariant</item> - - </style> - - <style name="SettingsLibButtonStyle.Expressive.Outline.Large"> - <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item> - <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item> - <item name="android:textSize">16sp</item> - </style> - - <style name="SettingsLibButtonStyle.Expressive.Outline.Extra" - parent="@style/SettingsLibButtonStyle.Expressive.Outline.Large"> - <item name="android:layout_width">match_parent</item> - </style> - - <style name="SettingslibTextButtonStyle.Expressive" - parent="@style/Widget.Material3.Button.TextButton.Icon"> - <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item> - <item name="android:textSize">16sp</item> - <item name="android:textColor">@color/settingslib_materialColorOnSurface</item> - <item name="iconTint">@null</item> - <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item> - <item name="rippleColor">?android:attr/colorControlHighlight</item> - </style> - <style name="EntityHeader"> <item name="android:paddingTop">@dimen/settingslib_expressive_space_small4</item> <item name="android:paddingBottom">@dimen/settingslib_expressive_space_small1</item> @@ -327,12 +67,11 @@ <item name="android:gravity">center</item> <item name="android:ellipsize">marquee</item> <item name="android:textDirection">locale</item> - <item name="android:textAppearance">@style/TextAppearance.EntityHeaderTitle</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleLarge.Emphasized</item> </style> <style name="SettingslibTextAppearance.LinkableTextStyle.Expressive" - parent="@android:style/TextAppearance.DeviceDefault.WindowTitle"> - <item name="android:textSize">14sp</item> + parent="@style/TextAppearance.SettingsLib.LabelLarge"> <item name="android:textColor">?android:attr/colorAccent</item> </style> @@ -346,4 +85,14 @@ <item name="cardElevation">0dp</item> <item name="rippleColor">?android:attr/colorControlHighlight</item> </style> + + <style name="TextAppearance.SettingsLib.PreferenceTitle" + parent="@style/TextAppearance.SettingsLib.TitleMedium"> + <item name="android:textColor">@color/settingslib_text_color_primary</item> + </style> + + <style name="TextAppearance.SettingsLib.PreferenceSummary" + parent="@style/TextAppearance.SettingsLib.BodyMedium"> + <item name="android:textColor">@color/settingslib_text_color_secondary</item> + </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml index fea8739ab37d..14f214a96435 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes_expressive.xml @@ -18,8 +18,8 @@ <resources> <style name="Theme.SettingsBase.Expressive"> <!-- Set up Preference title text style --> - <!--item name="android:textAppearanceListItem">@style/TextAppearance.PreferenceTitle.SettingsLib</item--> - <!--item name="android:textAppearanceListItemSecondary">@style/textAppearanceListItemSecondary</item--> + <item name="android:textAppearanceListItem">@style/TextAppearance.SettingsLib.PreferenceTitle</item> + <item name="android:textAppearanceListItemSecondary">@style/TextAppearance.SettingsLib.PreferenceSummary</item> <!-- Set up list item padding --> <item name="android:listPreferredItemPaddingStart">@dimen/settingslib_expressive_space_small1</item> diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/attrs_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values/attrs_expressive.xml index 857dd7953234..857dd7953234 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/attrs_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/attrs_expressive.xml diff --git a/packages/SettingsLib/SettingsTheme/res/values/colors.xml b/packages/SettingsLib/SettingsTheme/res/values/colors.xml new file mode 100644 index 000000000000..c5c613b4b329 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values/colors.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <color name="settingslib_error_0">#FFFFFF</color> + <color name="settingslib_error_10">#FFFBFF</color> + <color name="settingslib_error_50">#FFEDEA</color> + <color name="settingslib_error_100">#FFDAD6</color> + <color name="settingslib_error_200">#FFB4AB</color> + <color name="settingslib_error_300">#FF897D</color> + <color name="settingslib_error_400">#FF5449</color> + <color name="settingslib_error_500">#DE3730</color> + <color name="settingslib_error_600">#BA1A1A</color> + <color name="settingslib_error_700">#93000A</color> + <color name="settingslib_error_800">#690005</color> + <color name="settingslib_error_900">#410002</color> + <color name="settingslib_error_1000">#000000</color> + + <color name="settingslib_materialColorPrimary">#006B5F</color> + <color name="settingslib_materialColorOnPrimary">#FFFFFF</color> + <color name="settingslib_materialColorPrimaryContainer">#C5EAE2</color> + <color name="settingslib_materialColorOnPrimaryContainer">#00201C</color> + <color name="settingslib_materialColorPrimaryInverse">#83D6C7</color> + <color name="settingslib_materialColorPrimaryFixed">#C5EAE2</color> + <color name="settingslib_materialColorPrimaryFixedDim">#82D5C6</color> + <color name="settingslib_materialColorOnPrimaryFixed">#00201C</color> + <color name="settingslib_materialColorOnPrimaryFixedVariant">#005047</color> + <color name="settingslib_materialColorSecondary">#4A635E</color> + <color name="settingslib_materialColorOnSecondary">#FFFFFF</color> + <color name="settingslib_materialColorSecondaryContainer">#CCE8E2</color> + <color name="settingslib_materialColorOnSecondaryContainer">#051F1B</color> + <color name="settingslib_materialColorSecondaryFixed">#CCE8E2</color> + <color name="settingslib_materialColorSecondaryFixedDim">#B1CCC6</color> + <color name="settingslib_materialColorOnSecondaryFixed">#051F1B</color> + <color name="settingslib_materialColorOnSecondaryFixedVariant">#334C47</color> + <color name="settingslib_materialColorTertiary">#456179</color> + <color name="settingslib_materialColorOnTertiary">#FFFFFF</color> + <color name="settingslib_materialColorTertiaryContainer">#CBE6FF</color> + <color name="settingslib_materialColorOnTertiaryContainer">#001E31</color> + <color name="settingslib_materialColorTertiaryFixed">#CBE5FF</color> + <color name="settingslib_materialColorTertiaryFixedDim">#ADCAE5</color> + <color name="settingslib_materialColorOnTertiaryFixed">#001E31</color> + <color name="settingslib_materialColorOnTertiaryFixedVariant">#2D4A60</color> + <color name="settingslib_materialColorError">#B3261E</color> + <color name="settingslib_materialColorOnError">#FFFFFF</color> + <color name="settingslib_materialColorErrorContainer">#F9DEDC</color> + <color name="settingslib_materialColorOnErrorContainer">#3A0A08</color> + <color name="settingslib_materialColorOutline">#777777</color> + <color name="settingslib_materialColorOutlineVariant">#C7C6C5</color> + <color name="settingslib_materialColorBackground">#F9FAF8</color> + <color name="settingslib_materialColorOnBackground">#1B1B1B</color> + <color name="settingslib_materialColorSurface">#F9FAF8</color> + <color name="settingslib_materialColorOnSurface">#1B1B1B</color> + <color name="settingslib_materialColorSurfaceVariant">#E3E3E3</color> + <color name="settingslib_materialColorOnSurfaceVariant">#474747</color> + <color name="settingslib_materialColorSurfaceInverse">#303030</color> + <color name="settingslib_materialColorOnSurfaceInverse">#F1F1F1</color> + <color name="settingslib_materialColorSurfaceBright">#F9FAF8</color> + <color name="settingslib_materialColorSurfaceDim">#DADADA</color> + <color name="settingslib_materialColorSurfaceContainer">#EEEEEE</color> + <color name="settingslib_materialColorSurfaceContainerLow">#F4F4F4</color> + <color name="settingslib_materialColorSurfaceContainerLowest">#FFFFFF</color> + <color name="settingslib_materialColorSurfaceContainerHigh">#E8E8E8</color> + <color name="settingslib_materialColorSurfaceContainerHighest">#E3E3E3</color> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values/config.xml b/packages/SettingsLib/SettingsTheme/res/values/config.xml index e73dcc0cc559..53da49180219 100644 --- a/packages/SettingsLib/SettingsTheme/res/values/config.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/config.xml @@ -16,4 +16,7 @@ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <bool name="settingslib_config_icon_space_reserved">true</bool> + + <!-- Name of a font family to use for headlines in SettingsLib. --> + <string name="settingslib_config_headlineFontFamily" translatable="false"></string> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/dimens_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens_expressive.xml index 0542c510fa63..0542c510fa63 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/dimens_expressive.xml +++ b/packages/SettingsLib/SettingsTheme/res/values/dimens_expressive.xml diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml new file mode 100644 index 000000000000..f73e100906c8 --- /dev/null +++ b/packages/SettingsLib/SettingsTheme/res/values/styles_expressive.xml @@ -0,0 +1,253 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:tools="http://schemas.android.com/tools"> + <style name="TextAppearance.SettingsLib.DisplayLarge" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">57sp</item> + <item name="android:letterSpacing">-0.00438596</item> + <item name="android:lineHeight" tools:targetApi="28">64sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplayMedium" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">45sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">52sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplaySmall" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">36sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">44sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.HeadlineLarge" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">32sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">40sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineMedium" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">28sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">36sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineSmall" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">24sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">32sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.TitleLarge" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item> + <item name="android:textSize">22sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">28sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleMedium" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight" tools:targetApi="28">24sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleSmall" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.LabelLarge" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelMedium" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.04166667</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelSmall" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textSize">11sp</item> + <item name="android:letterSpacing">0.04545455</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.BodyLarge" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.03125</item> + <item name="android:lineHeight" tools:targetApi="28">24sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodyMedium" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.01785714</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodySmall" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.03333333</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.DisplayLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">57sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">64sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplayMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">45sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">52sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.DisplaySmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">36sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">44sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.HeadlineLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">32sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">40sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">28sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">36sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.HeadlineSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">24sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">32sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.TitleLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"> + <item name="android:textSize">22sp</item> + <item name="android:letterSpacing">0</item> + <item name="android:lineHeight" tools:targetApi="28">28sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight" tools:targetApi="28">24sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.TitleSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.LabelLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.00714286</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.04166667</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.LabelSmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault"> + <item name="android:textStyle">bold</item> + <item name="android:textSize">11sp</item> + <item name="android:letterSpacing">0.04545455</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> + + <style name="TextAppearance.SettingsLib.BodyLarge.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">16sp</item> + <item name="android:letterSpacing">0.009375</item> + <item name="android:lineHeight" tools:targetApi="28">24sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodyMedium.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">14sp</item> + <item name="android:letterSpacing">0.01785714</item> + <item name="android:lineHeight" tools:targetApi="28">20sp</item> + <item name="android:textAllCaps">false</item> + </style> + <style name="TextAppearance.SettingsLib.BodySmall.Emphasized" + parent="@android:style/TextAppearance.DeviceDefault.Medium"> + <item name="android:textStyle">normal</item> + <item name="android:textSize">12sp</item> + <item name="android:letterSpacing">0.03333333</item> + <item name="android:lineHeight" tools:targetApi="28">16sp</item> + <item name="android:textAllCaps">false</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts index 02e190417853..cf695d0543c7 100644 --- a/packages/SettingsLib/Spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/build.gradle.kts @@ -14,14 +14,13 @@ * limitations under the License. */ -import com.android.build.api.dsl.CommonExtension import com.android.build.gradle.BaseExtension import com.android.build.gradle.api.AndroidBasePlugin -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false + alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.kotlin.android) apply false } @@ -51,23 +50,4 @@ subprojects { } } } - - afterEvaluate { - plugins.withType<AndroidBasePlugin> { - the(CommonExtension::class).apply { - if (buildFeatures.compose == true) { - composeOptions { - kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get() - } - } - } - } - } - - tasks.withType<KotlinCompile> { - kotlinOptions { - jvmTarget = libs.versions.jvm.get() - freeCompilerArgs = listOf("-Xjvm-default=all") - } - } } diff --git a/packages/SettingsLib/Spa/gallery/build.gradle.kts b/packages/SettingsLib/Spa/gallery/build.gradle.kts index a1151a5e827e..19aa710babd3 100644 --- a/packages/SettingsLib/Spa/gallery/build.gradle.kts +++ b/packages/SettingsLib/Spa/gallery/build.gradle.kts @@ -16,6 +16,7 @@ plugins { alias(libs.plugins.android.application) + alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlin.android) } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageProvider.kt index f7649b91f558..17f996567ce7 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageProvider.kt @@ -20,11 +20,13 @@ import android.os.Bundle import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.DisabledByDefault import androidx.compose.runtime.Composable +import androidx.compose.runtime.IntState import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.produceState import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -33,8 +35,11 @@ import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.gallery.R +import com.android.settingslib.spa.widget.preference.ListPreferenceModel +import com.android.settingslib.spa.widget.preference.ListPreferenceOption import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.preference.RadioPreferences import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Category import com.android.settingslib.spa.widget.ui.SettingsIcon @@ -103,6 +108,22 @@ object PreferencePageProvider : SettingsPageProvider { override val summary = { ticks.toString() } }) } + val selectedId = rememberSaveable { mutableIntStateOf(0) } + RadioPreferences( + object : ListPreferenceModel { + override val title: String = "RadioPreferences" + override val options: List<ListPreferenceOption> = + listOf( + ListPreferenceOption(id = 0, text = "option1"), + ListPreferenceOption(id = 1, text = "option2"), + ListPreferenceOption(id = 2, text = "option3"), + ) + override val selectedId: IntState = selectedId + override val onIdSelected: (Int) -> Unit = { + selectedId.intValue = it + } + } + ) } } diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml index 74811d3ae7a6..04ef96a89843 100644 --- a/packages/SettingsLib/Spa/gradle/libs.versions.toml +++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml @@ -15,12 +15,11 @@ # [versions] -agp = "8.7.2" -compose-compiler = "1.5.11" +agp = "8.7.3" dexmaker-mockito = "2.28.3" jvm = "17" -kotlin = "1.9.23" -truth = "1.1.5" +kotlin = "2.0.21" +truth = "1.4.4" [libraries] dexmaker-mockito = { module = "com.linkedin.dexmaker:dexmaker-mockito", version.ref = "dexmaker-mockito" } @@ -29,4 +28,5 @@ truth = { module = "com.google.truth:truth", version.ref = "truth" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index 1f32ad6622a2..a0bbb0ca9ae6 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -16,6 +16,7 @@ plugins { alias(libs.plugins.android.library) + alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlin.android) jacoco } @@ -41,9 +42,6 @@ android { manifest.srcFile("../tests/AndroidManifest.xml") } } - buildFeatures { - compose = true - } buildTypes { getByName("debug") { enableAndroidTestCoverage = true @@ -63,7 +61,7 @@ dependencies { api("androidx.lifecycle:lifecycle-runtime-compose") api("androidx.navigation:navigation-compose:2.9.0-alpha03") api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") - api("com.google.android.material:material:1.12.0") + api("com.google.android.material:material:1.13.0-alpha08") debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion") implementation("com.airbnb.android:lottie-compose:6.4.0") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt index 8300ce855988..ec94df057b77 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt @@ -16,28 +16,34 @@ package com.android.settingslib.spa.widget.preference -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.IntState +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.Role +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.compose.thenIf import com.android.settingslib.spa.framework.theme.SettingsDimension -import com.android.settingslib.spa.widget.ui.CategoryTitle +import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled +import com.android.settingslib.spa.widget.ui.Category import com.android.settingslib.spa.widget.ui.SettingsListItem @Composable fun RadioPreferences(model: ListPreferenceModel) { - CategoryTitle(title = model.title) - Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) - Column(modifier = Modifier.selectableGroup()) { + Category(modifier = Modifier.selectableGroup(), title = model.title) { for (option in model.options) { Radio2(option, model.selectedId.intValue, model.enabled()) { model.onIdSelected(it) @@ -54,20 +60,52 @@ fun Radio2( onIdSelected: (id: Int) -> Unit, ) { val selected = option.id == selectedId + val surfaceBright = MaterialTheme.colorScheme.surfaceBright Row( - modifier = Modifier - .fillMaxWidth() - .selectable( - selected = selected, - enabled = enabled, - onClick = { onIdSelected(option.id) }, - role = Role.RadioButton, - ) - .padding(SettingsDimension.dialogItemPadding), + modifier = + Modifier.fillMaxWidth() + .thenIf(isSpaExpressiveEnabled) { + Modifier.heightIn(min = SettingsDimension.preferenceMinHeight) + .background(surfaceBright) + } + .selectable( + selected = selected, + enabled = enabled, + onClick = { onIdSelected(option.id) }, + role = Role.RadioButton, + ) + .then( + if (isSpaExpressiveEnabled) Modifier.padding(SettingsDimension.itemPadding) + else Modifier.padding(SettingsDimension.dialogItemPadding) + ), verticalAlignment = Alignment.CenterVertically, ) { RadioButton(selected = selected, onClick = null, enabled = enabled) - Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) + Spacer( + modifier = + Modifier.width( + if (isSpaExpressiveEnabled) SettingsDimension.paddingExtraSmall6 + else SettingsDimension.itemDividerHeight + ) + ) SettingsListItem(text = option.text, enabled = enabled) } -}
\ No newline at end of file +} + +@Preview +@Composable +private fun RadioPreferencePreview() { + RadioPreferences( + object : ListPreferenceModel { + override val title: String = "Title" + override val options: List<ListPreferenceOption> = + listOf( + ListPreferenceOption(id = 0, text = "option1"), + ListPreferenceOption(id = 1, text = "option2"), + ListPreferenceOption(id = 2, text = "option3"), + ) + override val selectedId: IntState = remember { mutableIntStateOf(0) } + override val onIdSelected: (Int) -> Unit = {} + } + ) +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt index 96d2abb70391..62bc00a8b347 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt @@ -76,7 +76,7 @@ fun CategoryTitle(title: String) { * visually separates groups of items. */ @Composable -fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit) { +fun Category(title: String? = null, modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) { var displayTitle by remember { mutableStateOf(false) } Column( modifier = @@ -90,7 +90,7 @@ fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit) if (title != null && displayTitle) CategoryTitle(title = title) Column( modifier = - Modifier.onGloballyPositioned { coordinates -> + modifier.onGloballyPositioned { coordinates -> displayTitle = coordinates.size.height > 0 } .then( @@ -162,7 +162,7 @@ internal val LocalIsInCategory = compositionLocalOf { false } @Composable private fun CategoryPreview() { SettingsTheme { - Category("Appearance") { + Category(title = "Appearance") { Preference( object : PreferenceModel { override val title = "Title" diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt index 2f98b02b8dd5..d187017f5021 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt @@ -43,7 +43,9 @@ class RadioPreferencesTest { RadioPreferences(remember { object : ListPreferenceModel { override val title = TITLE - override val options = emptyList<ListPreferenceOption>() + override val options = listOf( + ListPreferenceOption(id = 1, text = "A") + ) override val selectedId = mutableIntStateOf(0) override val onIdSelected: (Int) -> Unit = {} } diff --git a/packages/SettingsLib/Spa/testutils/build.gradle.kts b/packages/SettingsLib/Spa/testutils/build.gradle.kts index cce82354a51f..7dbd320c7d5a 100644 --- a/packages/SettingsLib/Spa/testutils/build.gradle.kts +++ b/packages/SettingsLib/Spa/testutils/build.gradle.kts @@ -16,6 +16,7 @@ plugins { alias(libs.plugins.android.library) + alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlin.android) } @@ -30,9 +31,6 @@ android { manifest.srcFile("AndroidManifest.xml") } } - buildFeatures { - compose = true - } } dependencies { diff --git a/packages/SettingsLib/StatusBannerPreference/res/layout/settingslib_expressive_preference_statusbanner.xml b/packages/SettingsLib/StatusBannerPreference/res/layout/settingslib_expressive_preference_statusbanner.xml index 9a3e5b9e1e50..083b862e8a5c 100644 --- a/packages/SettingsLib/StatusBannerPreference/res/layout/settingslib_expressive_preference_statusbanner.xml +++ b/packages/SettingsLib/StatusBannerPreference/res/layout/settingslib_expressive_preference_statusbanner.xml @@ -72,7 +72,7 @@ android:layout_height="wrap_content" android:hyphenationFrequency="normalFast" android:lineBreakWordStyle="phrase" - android:textAppearance="@style/SettingsLibTextAppearance.Emphasized.Title.Large"/> + android:textAppearance="@style/TextAppearance.SettingsLib.TitleLarge.Emphasized"/> <TextView android:id="@android:id/summary" @@ -81,7 +81,7 @@ android:hyphenationFrequency="normalFast" android:lineBreakWordStyle="phrase" android:maxLines="3" - android:textAppearance="@style/SettingsLibTextAppearance.Primary.Body.Medium"/> + android:textAppearance="@style/TextAppearance.SettingsLib.BodyMedium"/> </LinearLayout> </LinearLayout> diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index c1f254ad2b34..1a043d5015b2 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -187,3 +187,13 @@ flag { description: "Enable the connection status report for a set of hearing device." bug: "357882387" } + +flag { + name: "ignore_a2dp_disconnection_for_android_auto" + namespace: "cross_device_experiences" + description: "Do not show problem connecting message when Android Auto disconnect A2DP" + bug: "381981752" + metadata { + purpose: PURPOSE_BUGFIX + } +} 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/AmbientVolumeController.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeController.java new file mode 100644 index 000000000000..7f0c1263570e --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/AmbientVolumeController.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static android.bluetooth.AudioInputControl.MUTE_DISABLED; +import static android.bluetooth.AudioInputControl.MUTE_MUTED; +import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED; + +import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME; + +import android.bluetooth.AudioInputControl; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.util.ArrayMap; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * AmbientVolumeController manages the {@link AudioInputControl}s of + * {@link AudioInputControl#AUDIO_INPUT_TYPE_AMBIENT} on the remote device. + */ +public class AmbientVolumeController implements LocalBluetoothProfileManager.ServiceListener { + + private static final boolean DEBUG = true; + private static final String TAG = "AmbientController"; + + private final LocalBluetoothProfileManager mProfileManager; + private final VolumeControlProfile mVolumeControlProfile; + private final Map<BluetoothDevice, List<AudioInputControl>> mDeviceAmbientControlsMap = + new ArrayMap<>(); + private final Map<BluetoothDevice, AmbientCallback> mDeviceCallbackMap = new ArrayMap<>(); + final Map<BluetoothDevice, RemoteAmbientState> mDeviceAmbientStateMap = + new ArrayMap<>(); + @Nullable + private final AmbientVolumeControlCallback mCallback; + + public AmbientVolumeController( + @NonNull LocalBluetoothProfileManager profileManager, + @Nullable AmbientVolumeControlCallback callback) { + mProfileManager = profileManager; + mVolumeControlProfile = profileManager.getVolumeControlProfile(); + if (mVolumeControlProfile != null && !mVolumeControlProfile.isProfileReady()) { + mProfileManager.addServiceListener(this); + } + mCallback = callback; + } + + @Override + public void onServiceConnected() { + if (mVolumeControlProfile != null && mVolumeControlProfile.isProfileReady()) { + mProfileManager.removeServiceListener(this); + if (mCallback != null) { + mCallback.onVolumeControlServiceConnected(); + } + } + } + + @Override + public void onServiceDisconnected() { + // Do nothing + } + + /** + * Registers the same {@link AmbientCallback} on all ambient control points of the remote + * device. The {@link AmbientCallback} will pass the event to registered + * {@link AmbientVolumeControlCallback} if exists. + * + * @param executor the executor to run the callback + * @param device the remote device + */ + public void registerCallback(@NonNull Executor executor, @NonNull BluetoothDevice device) { + AmbientCallback ambientCallback = new AmbientCallback(device, mCallback); + synchronized (mDeviceCallbackMap) { + mDeviceCallbackMap.put(device, ambientCallback); + } + + // register callback on all ambient input control points of this device + List<AudioInputControl> controls = getAmbientControls(device); + controls.forEach((control) -> { + try { + control.registerCallback(executor, ambientCallback); + } catch (IllegalArgumentException e) { + // The callback was already registered + Log.i(TAG, "Skip registering the callback, " + e.getMessage()); + } + }); + } + + /** + * Unregisters the {@link AmbientCallback} on all ambient control points of the remote + * device which is previously registered with {@link #registerCallback}. + * + * @param device the remote device + */ + public void unregisterCallback(@NonNull BluetoothDevice device) { + AmbientCallback ambientCallback; + synchronized (mDeviceCallbackMap) { + ambientCallback = mDeviceCallbackMap.remove(device); + } + if (ambientCallback == null) { + // callback not found, no need to unregister + return; + } + + // unregister callback on all ambient input control points of this device + List<AudioInputControl> controls = getAmbientControls(device); + controls.forEach(control -> { + try { + control.unregisterCallback(ambientCallback); + } catch (IllegalArgumentException e) { + // The callback was never registered or was already unregistered + Log.i(TAG, "Skip unregistering the callback, " + e.getMessage()); + } + }); + } + + /** + * Gets the gain setting max value from first ambient control point of the remote device. + * + * @param device the remote device + */ + public int getAmbientMax(@NonNull BluetoothDevice device) { + List<AudioInputControl> ambientControls = getAmbientControls(device); + int value = INVALID_VOLUME; + if (!ambientControls.isEmpty()) { + value = ambientControls.getFirst().getGainSettingMax(); + } + return value; + } + + /** + * Gets the gain setting min value from first ambient control point of the remote device. + * + * @param device the remote device + */ + public int getAmbientMin(@NonNull BluetoothDevice device) { + List<AudioInputControl> ambientControls = getAmbientControls(device); + int value = INVALID_VOLUME; + if (!ambientControls.isEmpty()) { + value = ambientControls.getFirst().getGainSettingMin(); + } + return value; + } + + /** + * Gets the latest values in {@link RemoteAmbientState}. + * + * @param device the remote device + * @return the {@link RemoteAmbientState} represents current remote ambient control point state + */ + @Nullable + public RemoteAmbientState refreshAmbientState(@Nullable BluetoothDevice device) { + if (device == null || !device.isConnected()) { + return null; + } + int gainSetting = getAmbient(device); + int mute = getMute(device); + return new RemoteAmbientState(gainSetting, mute); + } + + /** + * Gets the gain setting value from first ambient control point of the remote device and + * stores it in cached {@link RemoteAmbientState}. + * + * When any audio input point receives {@link AmbientCallback#onGainSettingChanged(int)} + * callback, only the changed value which is different from the value stored in the cached + * state will be notified to the {@link AmbientVolumeControlCallback} of this controller. + * + * @param device the remote device + */ + public int getAmbient(@NonNull BluetoothDevice device) { + List<AudioInputControl> ambientControls = getAmbientControls(device); + int value = INVALID_VOLUME; + if (!ambientControls.isEmpty()) { + synchronized (mDeviceAmbientStateMap) { + value = ambientControls.getFirst().getGainSetting(); + RemoteAmbientState state = mDeviceAmbientStateMap.getOrDefault(device, + new RemoteAmbientState(INVALID_VOLUME, MUTE_DISABLED)); + RemoteAmbientState updatedState = new RemoteAmbientState(value, state.mute); + mDeviceAmbientStateMap.put(device, updatedState); + } + } + return value; + } + + /** + * Sets the gain setting value to all ambient control points of the remote device. + * + * @param device the remote device + * @param value the gain setting value to be updated + */ + public void setAmbient(@NonNull BluetoothDevice device, int value) { + if (DEBUG) { + Log.d(TAG, "setAmbient, value:" + value + ", device:" + device); + } + List<AudioInputControl> ambientControls = getAmbientControls(device); + ambientControls.forEach(control -> control.setGainSetting(value)); + } + + /** + * Gets the mute state from first ambient control point of the remote device and + * stores it in cached {@link RemoteAmbientState}. The value will be one of + * {@link AudioInputControl.Mute}. + * + * When any audio input point receives {@link AmbientCallback#onMuteChanged(int)} callback, + * only the changed value which is different from the value stored in the cached state will + * be notified to the {@link AmbientVolumeControlCallback} of this controller. + * + * @param device the remote device + */ + public int getMute(@NonNull BluetoothDevice device) { + List<AudioInputControl> ambientControls = getAmbientControls(device); + int value = MUTE_DISABLED; + if (!ambientControls.isEmpty()) { + synchronized (mDeviceAmbientStateMap) { + value = ambientControls.getFirst().getMute(); + RemoteAmbientState state = mDeviceAmbientStateMap.getOrDefault(device, + new RemoteAmbientState(INVALID_VOLUME, MUTE_DISABLED)); + RemoteAmbientState updatedState = new RemoteAmbientState(state.gainSetting, value); + mDeviceAmbientStateMap.put(device, updatedState); + } + } + return value; + } + + /** + * Sets the mute state to all ambient control points of the remote device. + * + * @param device the remote device + * @param muted the mute state to be updated + */ + public void setMuted(@NonNull BluetoothDevice device, boolean muted) { + if (DEBUG) { + Log.d(TAG, "setMuted, muted:" + muted + ", device:" + device); + } + List<AudioInputControl> ambientControls = getAmbientControls(device); + ambientControls.forEach(control -> { + try { + control.setMute(muted ? MUTE_MUTED : MUTE_NOT_MUTED); + } catch (IllegalStateException e) { + // Sometimes remote will throw this exception due to initialization not done + // yet. Catch it to prevent crashes on UI. + Log.w(TAG, "Remote mute state is currently disabled."); + } + }); + } + + /** + * Checks if there's any valid ambient control point exists on the remote device + * + * @param device the remote device + */ + public boolean isAmbientControlAvailable(@NonNull BluetoothDevice device) { + final boolean hasAmbientControlPoint = !getAmbientControls(device).isEmpty(); + final boolean connectedToVcp = mVolumeControlProfile.getConnectionStatus(device) + == BluetoothProfile.STATE_CONNECTED; + return hasAmbientControlPoint && connectedToVcp; + } + + @NonNull + private List<AudioInputControl> getAmbientControls(@NonNull BluetoothDevice device) { + if (mVolumeControlProfile == null) { + return Collections.emptyList(); + } + synchronized (mDeviceAmbientControlsMap) { + if (mDeviceAmbientControlsMap.containsKey(device)) { + return mDeviceAmbientControlsMap.get(device); + } + List<AudioInputControl> ambientControls = + mVolumeControlProfile.getAudioInputControlServices(device).stream().filter( + this::isValidAmbientControl).toList(); + if (!ambientControls.isEmpty()) { + mDeviceAmbientControlsMap.put(device, ambientControls); + } + return ambientControls; + } + } + + private boolean isValidAmbientControl(AudioInputControl control) { + boolean isAmbientControl = + control.getAudioInputType() == AudioInputControl.AUDIO_INPUT_TYPE_AMBIENT; + boolean isManual = control.getGainMode() == AudioInputControl.GAIN_MODE_MANUAL + || control.getGainMode() == AudioInputControl.GAIN_MODE_MANUAL_ONLY; + boolean isActive = + control.getAudioInputStatus() == AudioInputControl.AUDIO_INPUT_STATUS_ACTIVE; + + return isAmbientControl && isManual && isActive; + } + + /** + * Callback providing information about the status and received events of + * {@link AmbientVolumeController}. + */ + public interface AmbientVolumeControlCallback { + + /** This method is called when the Volume Control Service is connected */ + default void onVolumeControlServiceConnected() { + } + + /** + * This method is called when one of the remote device's ambient control point's gain + * settings value is changed. + * + * @param device the remote device + * @param gainSettings the new gain setting value + */ + default void onAmbientChanged(@NonNull BluetoothDevice device, int gainSettings) { + } + + /** + * This method is called when one of the remote device's ambient control point's mute + * state is changed. + * + * @param device the remote device + * @param mute the new mute state + */ + default void onMuteChanged(@NonNull BluetoothDevice device, int mute) { + } + + /** + * This method is called when any command to the remote device's ambient control point + * is failed. + * + * @param device the remote device. + */ + default void onCommandFailed(@NonNull BluetoothDevice device) { + } + } + + /** + * A wrapper callback that will pass {@link AudioInputControl.AudioInputCallback} with extra + * device information to {@link AmbientVolumeControlCallback}. + */ + class AmbientCallback implements AudioInputControl.AudioInputCallback { + + private final BluetoothDevice mDevice; + private final AmbientVolumeControlCallback mCallback; + + AmbientCallback(@NonNull BluetoothDevice device, + @Nullable AmbientVolumeControlCallback callback) { + mDevice = device; + mCallback = callback; + } + + @Override + public void onGainSettingChanged(int gainSetting) { + if (mCallback != null) { + synchronized (mDeviceAmbientStateMap) { + RemoteAmbientState previousState = mDeviceAmbientStateMap.get(mDevice); + if (previousState.gainSetting != gainSetting) { + mCallback.onAmbientChanged(mDevice, gainSetting); + } + } + } + } + + @Override + public void onSetGainSettingFailed() { + Log.w(TAG, "onSetGainSettingFailed, device=" + mDevice); + if (mCallback != null) { + mCallback.onCommandFailed(mDevice); + } + } + + @Override + public void onMuteChanged(int mute) { + if (mCallback != null) { + synchronized (mDeviceAmbientStateMap) { + RemoteAmbientState previousState = mDeviceAmbientStateMap.get(mDevice); + if (previousState.mute != mute) { + mCallback.onMuteChanged(mDevice, mute); + } + } + } + } + + @Override + public void onSetMuteFailed() { + Log.w(TAG, "onSetMuteFailed, device=" + mDevice); + if (mCallback != null) { + mCallback.onCommandFailed(mDevice); + } + } + } + + public record RemoteAmbientState(int gainSetting, int mute) { + public boolean isMutable() { + return mute != MUTE_DISABLED; + } + public boolean isMuted() { + return mute == MUTE_MUTED; + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index 216574a5fff9..429e4c958f05 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -631,15 +631,15 @@ public class BluetoothUtils { assistantProfile.getAllConnectedDevices().stream() .map(deviceManager::findDevice) .filter(Objects::nonNull) - .map(CachedBluetoothDevice::getGroupId) + .map(BluetoothUtils::getGroupId) .collect(Collectors.toSet()); Set<Integer> activeGroupIds = leAudioProfile.getActiveDevices().stream() .map(deviceManager::findDevice) .filter(Objects::nonNull) - .map(CachedBluetoothDevice::getGroupId) + .map(BluetoothUtils::getGroupId) .collect(Collectors.toSet()); - int groupId = cachedDevice.getGroupId(); + int groupId = getGroupId(cachedDevice); return activeGroupIds.size() == 1 && !activeGroupIds.contains(groupId) && connectedGroupIds.size() == 2 diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 4eb0567c67d9..257c93505cfc 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; @@ -1580,6 +1591,12 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> private int getHearingDeviceSummaryRes(int leftBattery, int rightBattery, boolean shortSummary) { + if (getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_MONO + || getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) { + return !shortSummary && (getBatteryLevel() > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) + ? R.string.bluetooth_active_battery_level + : R.string.bluetooth_active_no_battery_level; + } boolean isLeftDeviceConnected = getConnectedHearingAidSide( HearingAidInfo.DeviceSide.SIDE_LEFT).isPresent(); boolean isRightDeviceConnected = getConnectedHearingAidSide( @@ -1635,8 +1652,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> @HearingAidInfo.DeviceSide int side) { return Stream.concat(Stream.of(this, mSubDevice), mMemberDevices.stream()) .filter(Objects::nonNull) - .filter(device -> device.getDeviceSide() == side - || device.getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) + .filter(device -> device.getDeviceSide() == side) .filter(device -> device.getDevice().isConnected()) // For hearing aids, we should expect only one device assign to one side, but if // it happens, we don't care which one. @@ -2031,4 +2047,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/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 7fdb32cb63e9..b754706fb9a1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -153,7 +153,7 @@ public class CachedBluetoothDeviceManager { /** * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter. * - * @param CachedBluetoothDevice device + * @param device the remote device * @return Device summary, or if the pair does not exist or if it is not a hearing aid or * a CSIP set member, then {@code null}. */ @@ -394,6 +394,7 @@ public class CachedBluetoothDeviceManager { } public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) { + mHearingAidDeviceManager.clearLocalDataIfNeeded(device); device.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID); CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device); // Should iterate through the cloned set to avoid ConcurrentModificationException diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java index fa28cf6c8a76..1ca4c2b39a70 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java @@ -18,7 +18,6 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothHapClient; import android.bluetooth.BluetoothHearingAid; -import android.bluetooth.BluetoothLeAudio; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.bluetooth.le.ScanFilter; @@ -308,6 +307,10 @@ public class HearingAidDeviceManager { } } + void clearLocalDataIfNeeded(CachedBluetoothDevice device) { + HearingDeviceLocalDataManager.clear(mContext, device.getDevice()); + } + private void setAudioRoutingConfig(CachedBluetoothDevice device) { AudioDeviceAttributes hearingDeviceAttributes = mRoutingHelper.getMatchedHearingDeviceAttributes(device); @@ -428,8 +431,7 @@ public class HearingAidDeviceManager { p -> p instanceof HapClientProfile)) { int audioLocation = leAudioProfile.getAudioLocation(cachedDevice.getDevice()); int hearingAidType = hapClientProfile.getHearingAidType(cachedDevice.getDevice()); - if (audioLocation != BluetoothLeAudio.AUDIO_LOCATION_INVALID - && hearingAidType != HapClientProfile.HearingAidType.TYPE_INVALID) { + if (hearingAidType != HapClientProfile.HearingAidType.TYPE_INVALID) { final HearingAidInfo info = new HearingAidInfo.Builder() .setLeAudioLocation(audioLocation) .setHapDeviceType(hearingAidType) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java index ef08c924b844..8399824f11e9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java @@ -34,6 +34,7 @@ public class HearingAidInfo { DeviceSide.SIDE_LEFT, DeviceSide.SIDE_RIGHT, DeviceSide.SIDE_LEFT_AND_RIGHT, + DeviceSide.SIDE_MONO }) /** Side definition for hearing aids. */ @@ -42,6 +43,7 @@ public class HearingAidInfo { int SIDE_LEFT = 0; int SIDE_RIGHT = 1; int SIDE_LEFT_AND_RIGHT = 2; + int SIDE_MONO = 3; } @Retention(java.lang.annotation.RetentionPolicy.SOURCE) @@ -124,6 +126,9 @@ public class HearingAidInfo { @DeviceSide private static int convertLeAudioLocationToInternalSide(int leAudioLocation) { + if (leAudioLocation == BluetoothLeAudio.AUDIO_LOCATION_MONO) { + return DeviceSide.SIDE_MONO; + } boolean isLeft = (leAudioLocation & LE_AUDIO_LOCATION_LEFT) != 0; boolean isRight = (leAudioLocation & LE_AUDIO_LOCATION_RIGHT) != 0; if (isLeft && isRight) { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java index 7a64965334c9..6725558cd2bd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManager.java @@ -86,6 +86,17 @@ public class HearingDeviceLocalDataManager { mSettingsObserver = new SettingsObserver(ThreadUtils.getUiThreadHandler()); } + /** + * Clears the local data of the device. This method should be called when the device is + * unpaired. + */ + public static void clear(@NonNull Context context, @NonNull BluetoothDevice device) { + HearingDeviceLocalDataManager manager = new HearingDeviceLocalDataManager(context); + manager.getLocalDataFromSettings(); + manager.remove(device); + manager.putAmbientVolumeSettings(); + } + /** Starts the manager. Loads the data from Settings and start observing any changes. */ public synchronized void start() { if (mIsStarted) { @@ -141,6 +152,7 @@ public class HearingDeviceLocalDataManager { * Puts the local data of the corresponding hearing device. * * @param device the device to update the local data + * @param data the local data to be stored */ private void put(BluetoothDevice device, Data data) { if (device == null) { @@ -148,7 +160,11 @@ public class HearingDeviceLocalDataManager { } synchronized (sLock) { final String addr = device.getAnonymizedAddress(); - mAddrToDataMap.put(addr, data); + if (data == null) { + mAddrToDataMap.remove(addr); + } else { + mAddrToDataMap.put(addr, data); + } if (mListener != null && mListenerExecutor != null) { mListenerExecutor.execute(() -> mListener.onDeviceLocalDataChange(addr, data)); } @@ -156,6 +172,24 @@ public class HearingDeviceLocalDataManager { } /** + * Removes the local data of the corresponding hearing device. + * + * @param device the device to remove the local data + */ + private void remove(BluetoothDevice device) { + if (device == null) { + return; + } + synchronized (sLock) { + final String addr = device.getAnonymizedAddress(); + mAddrToDataMap.remove(addr); + if (mListener != null && mListenerExecutor != null) { + mListenerExecutor.execute(() -> mListener.onDeviceLocalDataChange(addr, null)); + } + } + } + + /** * Updates the ambient volume of the corresponding hearing device. This should be called after * {@link #start()} is called(). * diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java index a4c5a00dc53e..5bcdcc09206b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcastAssistant.java @@ -32,7 +32,9 @@ import android.content.Context; import android.os.Build; import android.util.Log; +import androidx.annotation.IntRange; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.android.settingslib.R; @@ -372,6 +374,27 @@ public class LocalBluetoothLeBroadcastAssistant implements LocalBluetoothProfile } /** + * Gets the {@link BluetoothLeBroadcastMetadata} of a specified source added to this sink. + * + * @param sink Broadcast Sink device + * @param sourceId Broadcast source id + * @return metadata {@link BluetoothLeBroadcastMetadata} associated with the specified source. + */ + public @Nullable BluetoothLeBroadcastMetadata getSourceMetadata( + @NonNull BluetoothDevice sink, @IntRange(from = 0x00, to = 0xFF) int sourceId) { + if (mService == null) { + Log.d(TAG, "The BluetoothLeBroadcastAssistant is null"); + return null; + } + try { + return mService.getSourceMetadata(sink, sourceId); + } catch (IllegalArgumentException | NoSuchMethodError e) { + Log.w(TAG, "Error calling getSourceMetadata()", e); + } + return null; + } + + /** * Register Broadcast Assistant Callbacks to track its state and receivers * * @param executor Executor object for callback 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/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index a03977c16f66..785bcbf5a91c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -21,15 +21,26 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NO import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY; + import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.admin.Authority; +import android.app.admin.DeviceAdminAuthority; import android.app.admin.DevicePolicyManager; +import android.app.admin.DpcAuthority; +import android.app.admin.EnforcingAdmin; +import android.app.admin.RoleAuthority; +import android.app.admin.UnknownAuthority; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,8 +48,13 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -52,6 +68,8 @@ import java.util.Collections; @RunWith(RobolectricTestRunner.class) public class RestrictedLockUtilsTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Mock private Context mContext; @@ -66,6 +84,7 @@ public class RestrictedLockUtilsTest { private final int mUserId = 194; private final int mProfileId = 160; + private final String mPackage = "test.pkg"; private final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class"); private final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class"); @@ -85,6 +104,7 @@ public class RestrictedLockUtilsTest { RestrictedLockUtilsInternal.sProxy = mProxy; } + @RequiresFlagsDisabled(android.security.Flags.FLAG_AAPM_API) @Test public void checkIfRestrictionEnforced_deviceOwner() throws PackageManager.NameNotFoundException { @@ -109,6 +129,7 @@ public class RestrictedLockUtilsTest { assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); } + @RequiresFlagsDisabled(android.security.Flags.FLAG_AAPM_API) @Test public void checkIfRestrictionEnforced_profileOwner() throws PackageManager.NameNotFoundException { @@ -133,6 +154,125 @@ public class RestrictedLockUtilsTest { assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); } + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void checkIfRestrictionEnforced_getEnforcingAdminExists() { + UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId, + UserManager.RESTRICTION_SOURCE_PROFILE_OWNER); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + final EnforcingAdmin enforcingAdmin = new EnforcingAdmin(mPackage, + UnknownAuthority.UNKNOWN_AUTHORITY, UserHandle.of(mUserId), mAdmin1); + + when(mUserManager.getUserRestrictionSources(userRestriction, + UserHandle.of(mUserId))) + .thenReturn(Collections.singletonList(enforcingUser)); + when(mDevicePolicyManager.getEnforcingAdmin(mUserId, userRestriction)) + .thenReturn(enforcingAdmin); + + EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + mContext, userRestriction, mUserId); + + assertThat(enforcedAdmin).isNotNull(); + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(userRestriction); + assertThat(enforcedAdmin.component).isEqualTo(enforcingAdmin.getComponentName()); + assertThat(enforcedAdmin.user).isEqualTo(enforcingAdmin.getUserHandle()); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void checkIfRestrictionEnforced_getEnforcingAdminReturnsNull_deviceOwner() + throws PackageManager.NameNotFoundException { + UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId, + UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + + when(mUserManager.getUserRestrictionSources(userRestriction, + UserHandle.of(mUserId))) + .thenReturn(Collections.singletonList(enforcingUser)); + when(mDevicePolicyManager.getEnforcingAdmin(mUserId, userRestriction)) + .thenReturn(null); + when(mContext.createPackageContextAsUser(any(), eq(0), + eq(UserHandle.of(mUserId)))) + .thenReturn(mContext); + + setUpDeviceOwner(mAdmin1, mUserId); + + EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal + .checkIfRestrictionEnforced(mContext, userRestriction, mUserId); + + assertThat(enforcedAdmin).isNotNull(); + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(userRestriction); + assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void checkIfRestrictionEnforced_getEnforcingAdminReturnsNull_profileOwner() + throws PackageManager.NameNotFoundException { + UserManager.EnforcingUser enforcingUser = new UserManager.EnforcingUser(mUserId, + UserManager.RESTRICTION_SOURCE_PROFILE_OWNER); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + + when(mUserManager.getUserRestrictionSources(userRestriction, + UserHandle.of(mUserId))) + .thenReturn(Collections.singletonList(enforcingUser)); + when(mDevicePolicyManager.getEnforcingAdmin(mUserId, userRestriction)) + .thenReturn(null); + when(mContext.createPackageContextAsUser(any(), eq(0), + eq(UserHandle.of(mUserId)))) + .thenReturn(mContext); + + setUpProfileOwner(mAdmin1); + + EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal + .checkIfRestrictionEnforced(mContext, userRestriction, mUserId); + + assertThat(enforcedAdmin).isNotNull(); + assertThat(enforcedAdmin.enforcedRestriction).isEqualTo(userRestriction); + assertThat(enforcedAdmin.component).isEqualTo(mAdmin1); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void isPolicyEnforcedByAdvancedProtection_notEnforced_returnsFalse() { + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + final Authority[] allNonAdvancedProtectionAuthorities = new Authority[] { + UnknownAuthority.UNKNOWN_AUTHORITY, + DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY, + DpcAuthority.DPC_AUTHORITY, + new RoleAuthority(Collections.singleton("some-role")) + }; + + for (Authority authority : allNonAdvancedProtectionAuthorities) { + final EnforcingAdmin enforcingAdmin = new EnforcingAdmin(mPackage, authority, + UserHandle.of(mUserId), mAdmin1); + + when(mDevicePolicyManager.getEnforcingAdmin(mUserId, userRestriction)) + .thenReturn(enforcingAdmin); + + assertWithMessage(authority + " is not an advanced protection authority") + .that(RestrictedLockUtilsInternal.isPolicyEnforcedByAdvancedProtection( + mContext, userRestriction, mUserId)) + .isFalse(); + } + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void isPolicyEnforcedByAdvancedProtection_enforced_returnsTrue() { + final Authority advancedProtectionAuthority = new UnknownAuthority( + ADVANCED_PROTECTION_SYSTEM_ENTITY); + final EnforcingAdmin advancedProtectionEnforcingAdmin = new EnforcingAdmin(mPackage, + advancedProtectionAuthority, UserHandle.of(mUserId), mAdmin1); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + + when(mDevicePolicyManager.getEnforcingAdmin(mUserId, userRestriction)) + .thenReturn(advancedProtectionEnforcingAdmin); + + assertThat(RestrictedLockUtilsInternal.isPolicyEnforcedByAdvancedProtection(mContext, + userRestriction, mUserId)).isTrue(); + } + @Test public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() { when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java index 7ad54e187ae5..dbbbd5bf8089 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java @@ -16,7 +16,10 @@ package com.android.settingslib; +import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY; + import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; @@ -26,10 +29,23 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.admin.Authority; +import android.app.admin.DeviceAdminAuthority; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyResourcesManager; +import android.app.admin.DpcAuthority; +import android.app.admin.EnforcingAdmin; +import android.app.admin.RoleAuthority; +import android.app.admin.UnknownAuthority; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.os.UserHandle; +import android.os.UserManager; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.view.View; import android.widget.TextView; @@ -37,14 +53,19 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import java.util.Collections; + @RunWith(RobolectricTestRunner.class) public class RestrictedPreferenceHelperTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Mock private Context mContext; @@ -57,6 +78,11 @@ public class RestrictedPreferenceHelperTest { @Mock private RestrictedTopLevelPreference mRestrictedTopLevelPreference; + private final String mPackage = "test.pkg"; + private final ComponentName mAdmin = new ComponentName("admin", "adminclass"); + private final Authority mAdvancedProtectionAuthority = new UnknownAuthority( + ADVANCED_PROTECTION_SYSTEM_ENTITY); + private PreferenceViewHolder mViewHolder; private RestrictedPreferenceHelper mHelper; @@ -71,6 +97,7 @@ public class RestrictedPreferenceHelperTest { mHelper = new RestrictedPreferenceHelper(mContext, mPreference, null); } + @RequiresFlagsDisabled(android.security.Flags.FLAG_AAPM_API) @Test public void bindPreference_disabled_shouldDisplayDisabledSummary() { final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS); @@ -101,6 +128,57 @@ public class RestrictedPreferenceHelperTest { verify(summaryView, never()).setVisibility(View.GONE); } + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void bindPreference_disabled_byAdvancedProtection_shouldDisplayDisabledSummary() { + final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + final RestrictedLockUtils.EnforcedAdmin enforcedAdmin = new RestrictedLockUtils + .EnforcedAdmin(/* component */ null, userRestriction, UserHandle.of( + UserHandle.myUserId())); + final EnforcingAdmin advancedProtectionEnforcingAdmin = new EnforcingAdmin(mPackage, + mAdvancedProtectionAuthority, UserHandle.of(UserHandle.myUserId()), mAdmin); + + when(mViewHolder.itemView.findViewById(android.R.id.summary)) + .thenReturn(summaryView); + when(mDevicePolicyManager.getEnforcingAdmin(UserHandle.myUserId(), userRestriction)) + .thenReturn(advancedProtectionEnforcingAdmin); + when(mContext.getString( + com.android.settingslib.widget.restricted.R.string.disabled_by_advanced_protection)) + .thenReturn("advanced_protection"); + + mHelper.useAdminDisabledSummary(true); + mHelper.setDisabledByAdmin(enforcedAdmin); + mHelper.onBindViewHolder(mViewHolder); + + verify(summaryView).setText("advanced_protection"); + verify(summaryView, never()).setVisibility(View.GONE); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void bindPreference_disabled_byAdmin_shouldDisplayDisabledSummary() { + final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS); + final EnforcingAdmin nonAdvancedProtectionEnforcingAdmin = new EnforcingAdmin(mPackage, + UnknownAuthority.UNKNOWN_AUTHORITY, UserHandle.of(UserHandle.myUserId()), mAdmin); + final String userRestriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY; + + when(mViewHolder.itemView.findViewById(android.R.id.summary)) + .thenReturn(summaryView); + when(mDevicePolicyManager.getEnforcingAdmin(UserHandle.myUserId(), userRestriction)) + .thenReturn(nonAdvancedProtectionEnforcingAdmin); + when(mContext.getString(R.string.disabled_by_admin_summary_text)) + .thenReturn("test"); + when(mDevicePolicyResourcesManager.getString(any(), any())).thenReturn("test"); + + mHelper.useAdminDisabledSummary(true); + mHelper.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin()); + mHelper.onBindViewHolder(mViewHolder); + + verify(summaryView).setText("test"); + verify(summaryView, never()).setVisibility(View.GONE); + } + @Test public void bindPreference_notDisabled_shouldNotHideSummary() { final TextView summaryView = mock(TextView.class, RETURNS_DEEP_STUBS); @@ -157,4 +235,74 @@ public class RestrictedPreferenceHelperTest { assertThat(mHelper.isDisabledByAdmin()).isTrue(); } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void setDisabledByAdmin_previousAndCurrentAdminsAreTheSame_returnsFalse() { + RestrictedLockUtils.EnforcedAdmin enforcedAdmin = + new RestrictedLockUtils.EnforcedAdmin(/* component */ null, + /* enforcedRestriction */ "some_restriction", /* userHandle */ null); + + mHelper.setDisabledByAdmin(enforcedAdmin); + + assertThat(mHelper.setDisabledByAdmin(enforcedAdmin)).isFalse(); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void setDisabledByAdmin_previousAndCurrentAdminsAreDifferent_returnsTrue() { + RestrictedLockUtils.EnforcedAdmin enforcedAdmin1 = + new RestrictedLockUtils.EnforcedAdmin(/* component */ null, + /* enforcedRestriction */ "some_restriction", /* userHandle */ null); + RestrictedLockUtils.EnforcedAdmin enforcedAdmin2 = + new RestrictedLockUtils.EnforcedAdmin(new ComponentName("pkg", "cls"), + /* enforcedRestriction */ "some_restriction", /* userHandle */ null); + + mHelper.setDisabledByAdmin(enforcedAdmin1); + + assertThat(mHelper.setDisabledByAdmin(enforcedAdmin2)).isTrue(); + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void isRestrictionEnforcedByAdvancedProtection_notEnforced_returnsFalse() { + final Authority[] allNonAdvancedProtectionAuthorities = new Authority[] { + UnknownAuthority.UNKNOWN_AUTHORITY, + DeviceAdminAuthority.DEVICE_ADMIN_AUTHORITY, + DpcAuthority.DPC_AUTHORITY, + new RoleAuthority(Collections.singleton("some-role")) + }; + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + + for (Authority authority : allNonAdvancedProtectionAuthorities) { + final EnforcingAdmin enforcingAdmin = new EnforcingAdmin(mPackage, authority, + UserHandle.of(UserHandle.myUserId()), mAdmin); + + when(mDevicePolicyManager.getEnforcingAdmin(UserHandle.myUserId(), userRestriction)) + .thenReturn(enforcingAdmin); + + mHelper.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin(/* component */ null, + userRestriction, UserHandle.of(UserHandle.myUserId()))); + + assertWithMessage(authority + " is not an advanced protection authority") + .that(mHelper.isRestrictionEnforcedByAdvancedProtection()) + .isFalse(); + } + } + + @RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API) + @Test + public void isRestrictionEnforcedByAdvancedProtection_enforced_returnsTrue() { + final EnforcingAdmin advancedProtectionEnforcingAdmin = new EnforcingAdmin(mPackage, + mAdvancedProtectionAuthority, UserHandle.of(UserHandle.myUserId()), mAdmin); + final String userRestriction = UserManager.DISALLOW_UNINSTALL_APPS; + + when(mDevicePolicyManager.getEnforcingAdmin(UserHandle.myUserId(), userRestriction)) + .thenReturn(advancedProtectionEnforcingAdmin); + + mHelper.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin(/* component */ null, + userRestriction, UserHandle.of(UserHandle.myUserId()))); + + assertThat(mHelper.isRestrictionEnforcedByAdvancedProtection()).isTrue(); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java new file mode 100644 index 000000000000..abc1d226972b --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/AmbientVolumeControllerTest.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.AudioInputControl; +import android.bluetooth.BluetoothDevice; +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** Tests for {@link AmbientVolumeController}. */ +@RunWith(RobolectricTestRunner.class) +public class AmbientVolumeControllerTest { + + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private static final String TEST_ADDRESS = "00:00:00:00:11"; + + @Mock + private LocalBluetoothProfileManager mProfileManager; + @Mock + private VolumeControlProfile mVolumeControlProfile; + @Mock + private AmbientVolumeController.AmbientVolumeControlCallback mCallback; + @Mock + private BluetoothDevice mDevice; + + private final Context mContext = ApplicationProvider.getApplicationContext(); + private AmbientVolumeController mVolumeController; + + @Before + public void setUp() { + when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile); + when(mDevice.getAddress()).thenReturn(TEST_ADDRESS); + when(mDevice.isConnected()).thenReturn(true); + mVolumeController = new AmbientVolumeController(mProfileManager, mCallback); + } + + @Test + public void onServiceConnected_notifyCallback() { + when(mVolumeControlProfile.isProfileReady()).thenReturn(true); + + mVolumeController.onServiceConnected(); + + verify(mCallback).onVolumeControlServiceConnected(); + } + + @Test + public void isAmbientControlAvailable_validControls_assertTrue() { + prepareValidAmbientControls(); + + assertThat(mVolumeController.isAmbientControlAvailable(mDevice)).isTrue(); + } + + @Test + public void isAmbientControlAvailable_streamingControls_assertFalse() { + prepareStreamingControls(); + + assertThat(mVolumeController.isAmbientControlAvailable(mDevice)).isFalse(); + } + + @Test + public void isAmbientControlAvailable_automaticAmbientControls_assertFalse() { + prepareAutomaticAmbientControls(); + + assertThat(mVolumeController.isAmbientControlAvailable(mDevice)).isFalse(); + } + + @Test + public void isAmbientControlAvailable_inactiveAmbientControls_assertFalse() { + prepareInactiveAmbientControls(); + + assertThat(mVolumeController.isAmbientControlAvailable(mDevice)).isFalse(); + } + + @Test + public void registerCallback_verifyRegisterOnAllControls() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.registerCallback(mContext.getMainExecutor(), mDevice); + + for (AudioInputControl control : controls) { + verify(control).registerCallback(any(Executor.class), any()); + } + } + + @Test + public void unregisterCallback_verifyUnregisterOnAllControls() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.registerCallback(mContext.getMainExecutor(), mDevice); + mVolumeController.unregisterCallback(mDevice); + + for (AudioInputControl control : controls) { + verify(control).unregisterCallback(any()); + } + } + + @Test + public void getAmbientMax_verifyGetOnFirstControl() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.getAmbientMax(mDevice); + + verify(controls.getFirst()).getGainSettingMax(); + } + + @Test + public void getAmbientMin_verifyGetOnFirstControl() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.getAmbientMin(mDevice); + + verify(controls.getFirst()).getGainSettingMin(); + } + + @Test + public void getAmbient_verifyGetOnFirstControl() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.getAmbient(mDevice); + + verify(controls.getFirst()).getGainSetting(); + } + + @Test + public void setAmbient_verifySetOnAllControls() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.setAmbient(mDevice, 10); + + for (AudioInputControl control : controls) { + verify(control).setGainSetting(10); + } + } + + @Test + public void getMute_verifyGetOnFirstControl() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.getMute(mDevice); + + verify(controls.getFirst()).getMute(); + } + + @Test + public void setMuted_true_verifySetOnAllControls() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.setMuted(mDevice, true); + + for (AudioInputControl control : controls) { + verify(control).setMute(AudioInputControl.MUTE_MUTED); + } + } + + @Test + public void setMuted_false_verifySetOnAllControls() { + List<AudioInputControl> controls = prepareValidAmbientControls(); + + mVolumeController.setMuted(mDevice, false); + + for (AudioInputControl control : controls) { + verify(control).setMute(AudioInputControl.MUTE_NOT_MUTED); + } + } + + @Test + public void ambientCallback_onGainSettingChanged_verifyCallbackIsCalledWhenStateChange() { + AmbientVolumeController.AmbientCallback ambientCallback = + mVolumeController.new AmbientCallback(mDevice, mCallback); + final int testAmbient = 10; + List<AudioInputControl> controls = prepareValidAmbientControls(); + when(controls.getFirst().getGainSetting()).thenReturn(testAmbient); + + mVolumeController.refreshAmbientState(mDevice); + ambientCallback.onGainSettingChanged(testAmbient); + verify(mCallback, never()).onAmbientChanged(mDevice, testAmbient); + + final int updatedTestAmbient = 20; + ambientCallback.onGainSettingChanged(updatedTestAmbient); + verify(mCallback).onAmbientChanged(mDevice, updatedTestAmbient); + } + + + @Test + public void ambientCallback_onSetAmbientFailed_verifyCallbackIsCalled() { + AmbientVolumeController.AmbientCallback ambientCallback = + mVolumeController.new AmbientCallback(mDevice, mCallback); + + ambientCallback.onSetGainSettingFailed(); + + verify(mCallback).onCommandFailed(mDevice); + } + + @Test + public void ambientCallback_onMuteChanged_verifyCallbackIsCalledWhenStateChange() { + AmbientVolumeController.AmbientCallback ambientCallback = + mVolumeController.new AmbientCallback(mDevice, mCallback); + final int testMute = 0; + List<AudioInputControl> controls = prepareValidAmbientControls(); + when(controls.getFirst().getMute()).thenReturn(testMute); + + mVolumeController.refreshAmbientState(mDevice); + ambientCallback.onMuteChanged(testMute); + verify(mCallback, never()).onMuteChanged(mDevice, testMute); + + final int updatedTestMute = 1; + ambientCallback.onMuteChanged(updatedTestMute); + verify(mCallback).onMuteChanged(mDevice, updatedTestMute); + } + + @Test + public void ambientCallback_onSetMuteFailed_verifyCallbackIsCalled() { + AmbientVolumeController.AmbientCallback ambientCallback = + mVolumeController.new AmbientCallback(mDevice, mCallback); + + ambientCallback.onSetMuteFailed(); + + verify(mCallback).onCommandFailed(mDevice); + } + + private List<AudioInputControl> prepareValidAmbientControls() { + List<AudioInputControl> controls = new ArrayList<>(); + final int controlsCount = 2; + for (int i = 0; i < controlsCount; i++) { + controls.add(prepareAudioInputControl( + AudioInputControl.AUDIO_INPUT_TYPE_AMBIENT, + AudioInputControl.GAIN_MODE_MANUAL, + AudioInputControl.AUDIO_INPUT_STATUS_ACTIVE)); + } + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn(controls); + return controls; + } + + private List<AudioInputControl> prepareStreamingControls() { + List<AudioInputControl> controls = new ArrayList<>(); + final int controlsCount = 2; + for (int i = 0; i < controlsCount; i++) { + controls.add(prepareAudioInputControl( + AudioInputControl.AUDIO_INPUT_TYPE_STREAMING, + AudioInputControl.GAIN_MODE_MANUAL, + AudioInputControl.AUDIO_INPUT_STATUS_ACTIVE)); + } + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn(controls); + return controls; + } + + private List<AudioInputControl> prepareAutomaticAmbientControls() { + List<AudioInputControl> controls = new ArrayList<>(); + final int controlsCount = 2; + for (int i = 0; i < controlsCount; i++) { + controls.add(prepareAudioInputControl( + AudioInputControl.AUDIO_INPUT_TYPE_STREAMING, + AudioInputControl.GAIN_MODE_AUTOMATIC, + AudioInputControl.AUDIO_INPUT_STATUS_ACTIVE)); + } + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn(controls); + return controls; + } + + private List<AudioInputControl> prepareInactiveAmbientControls() { + List<AudioInputControl> controls = new ArrayList<>(); + final int controlsCount = 2; + for (int i = 0; i < controlsCount; i++) { + controls.add(prepareAudioInputControl( + AudioInputControl.AUDIO_INPUT_TYPE_STREAMING, + AudioInputControl.GAIN_MODE_AUTOMATIC, + AudioInputControl.AUDIO_INPUT_STATUS_INACTIVE)); + } + when(mVolumeControlProfile.getAudioInputControlServices(mDevice)).thenReturn(controls); + return controls; + } + + private AudioInputControl prepareAudioInputControl(int type, int mode, int status) { + AudioInputControl control = mock(AudioInputControl.class); + when(control.getAudioInputType()).thenReturn(type); + when(control.getGainMode()).thenReturn(mode); + when(control.getAudioInputStatus()).thenReturn(status); + return control; + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java index 8cc997414d70..05f471f62f1d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java @@ -139,6 +139,11 @@ public class CachedBluetoothDeviceManagerTest { mCachedDevice1 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1)); mCachedDevice2 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2)); mCachedDevice3 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice3)); + + mHearingAidDeviceManager = spy(new HearingAidDeviceManager(mContext, mLocalBluetoothManager, + mCachedDeviceManager.mCachedDevices)); + mCachedDeviceManager.mHearingAidDeviceManager = mHearingAidDeviceManager; + doNothing().when(mHearingAidDeviceManager).clearLocalDataIfNeeded(any()); } /** @@ -338,6 +343,8 @@ public class CachedBluetoothDeviceManagerTest { // Call onDeviceUnpaired for the one in mCachedDevices. mCachedDeviceManager.onDeviceUnpaired(cachedDevice2); + + verify(mHearingAidDeviceManager).clearLocalDataIfNeeded(cachedDevice2); verify(mDevice1).removeBond(); } @@ -353,6 +360,8 @@ public class CachedBluetoothDeviceManagerTest { // Call onDeviceUnpaired for the one in mCachedDevices. mCachedDeviceManager.onDeviceUnpaired(cachedDevice1); + + verify(mHearingAidDeviceManager).clearLocalDataIfNeeded(cachedDevice1); verify(mDevice2).removeBond(); } @@ -406,9 +415,6 @@ public class CachedBluetoothDeviceManagerTest { */ @Test public void updateHearingAidDevices_directToHearingAidDeviceManager() { - mHearingAidDeviceManager = spy(new HearingAidDeviceManager(mContext, mLocalBluetoothManager, - mCachedDeviceManager.mCachedDevices)); - mCachedDeviceManager.mHearingAidDeviceManager = mHearingAidDeviceManager; mCachedDeviceManager.updateHearingAidsDevices(); verify(mHearingAidDeviceManager).updateHearingAidsDevices(); @@ -535,6 +541,7 @@ public class CachedBluetoothDeviceManagerTest { // Call onDeviceUnpaired for the one in mCachedDevices. mCachedDeviceManager.onDeviceUnpaired(cachedDevice1); + verify(mHearingAidDeviceManager).clearLocalDataIfNeeded(cachedDevice1); verify(mDevice2).removeBond(); assertThat(cachedDevice1.getGroupId()).isEqualTo( BluetoothCsipSetCoordinator.GROUP_ID_INVALID); @@ -559,6 +566,7 @@ public class CachedBluetoothDeviceManagerTest { // Call onDeviceUnpaired for the one in mCachedDevices. mCachedDeviceManager.onDeviceUnpaired(cachedDevice2); + verify(mHearingAidDeviceManager).clearLocalDataIfNeeded(cachedDevice2); verify(mDevice1).removeBond(); assertThat(cachedDevice2.getGroupId()).isEqualTo( BluetoothCsipSetCoordinator.GROUP_ID_INVALID); @@ -611,10 +619,7 @@ public class CachedBluetoothDeviceManagerTest { @Test public void onActiveDeviceChanged_validHiSyncId_callExpectedFunction() { - mHearingAidDeviceManager = spy(new HearingAidDeviceManager(mContext, mLocalBluetoothManager, - mCachedDeviceManager.mCachedDevices)); doNothing().when(mHearingAidDeviceManager).onActiveDeviceChanged(any()); - mCachedDeviceManager.mHearingAidDeviceManager = mHearingAidDeviceManager; when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); cachedDevice1.setHearingAidInfo( diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java index bf927a1eb4cc..eb73eee90f0d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java @@ -17,7 +17,6 @@ package com.android.settingslib.bluetooth; import static android.bluetooth.BluetoothHearingAid.HI_SYNC_ID_INVALID; import static android.bluetooth.BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT; -import static android.bluetooth.BluetoothLeAudio.AUDIO_LOCATION_INVALID; import static com.android.settingslib.bluetooth.HapClientProfile.HearingAidType.TYPE_BINAURAL; import static com.android.settingslib.bluetooth.HapClientProfile.HearingAidType.TYPE_INVALID; @@ -272,14 +271,14 @@ public class HearingAidDeviceManagerTest { * * Conditions: * 1) LeAudio hearing aid - * 2) Invalid audio location and device type + * 2) Invalid device type * Result: * Do not set hearing aid info to the device. */ @Test public void initHearingAidDeviceIfNeeded_leAudio_invalidInfo_notToSetHearingAidInfo() { when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile)); - when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_INVALID); + when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_FRONT_LEFT); when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_INVALID); mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1, null); @@ -506,14 +505,14 @@ public class HearingAidDeviceManagerTest { * * Conditions: * 1) LeAudio hearing aid - * 2) Invalid audio location and device type + * 2) Invalid device type * Result: * Do not set hearing aid info to the device. */ @Test public void updateHearingAidsDevices_leAudio_invalidInfo_notToSetHearingAidInfo() { when(mCachedDevice1.getProfiles()).thenReturn(List.of(mLeAudioProfile, mHapClientProfile)); - when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_INVALID); + when(mLeAudioProfile.getAudioLocation(mDevice1)).thenReturn(AUDIO_LOCATION_FRONT_LEFT); when(mHapClientProfile.getHearingAidType(mDevice1)).thenReturn(TYPE_INVALID); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java index b659c02a2540..6d83588e0f6e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingDeviceLocalDataManagerTest.java @@ -194,6 +194,19 @@ public class HearingDeviceLocalDataManagerTest { verify(mListener).onDeviceLocalDataChange(TEST_ADDRESS, newData); } + @Test + public void clear_dataIsRemoved() { + String settings = Settings.Global.getStringForUser(mContext.getContentResolver(), + Settings.Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, UserHandle.USER_SYSTEM); + assertThat(settings.contains(TEST_ADDRESS)).isTrue(); + + HearingDeviceLocalDataManager.clear(mContext, mDevice); + + settings = Settings.Global.getStringForUser(mContext.getContentResolver(), + Settings.Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, UserHandle.USER_SYSTEM); + assertThat(settings.contains(TEST_ADDRESS)).isFalse(); + } + private void prepareTestDataInSettings() { String data = generateSettingsString(TEST_ADDRESS, TEST_AMBIENT, TEST_GROUP_AMBIENT, TEST_AMBIENT_CONTROL_EXPANDED); 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/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 1f291cdefb03..731cb7269037 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -99,6 +99,7 @@ public class SecureSettings { Settings.Secure.RTT_CALLING_MODE, Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED, + Settings.Secure.MIRROR_BUILT_IN_DISPLAY, Settings.Secure.MATCH_CONTENT_FRAME_RATE, Settings.Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index abd5b9a4a4bb..039832cee6f2 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -150,6 +150,7 @@ public class SecureSettingsValidators { Secure.INCALL_POWER_BUTTON_BEHAVIOR, new DiscreteValueValidator(new String[] {"1", "2"})); VALIDATORS.put(Secure.MINIMAL_POST_PROCESSING_ALLOWED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.MIRROR_BUILT_IN_DISPLAY, BOOLEAN_VALIDATOR); VALIDATORS.put( Secure.MATCH_CONTENT_FRAME_RATE, new DiscreteValueValidator(new String[] {"0", "1", "2"})); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java index aca2c4ef2a49..91ac34ac8233 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java @@ -72,7 +72,6 @@ import java.util.regex.Pattern; public final class DeviceConfigService extends Binder { private static final List<String> sAconfigTextProtoFilesOnDevice = List.of( "/system/etc/aconfig_flags.pb", - "/system_ext/etc/aconfig_flags.pb", "/product/etc/aconfig_flags.pb", "/vendor/etc/aconfig_flags.pb"); @@ -133,12 +132,7 @@ public final class DeviceConfigService extends Binder { } pw.println("DeviceConfig provider: "); - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd)) { - DeviceConfig.dump(pfd, pw, /* prefix= */ " ", args); - } catch (IOException e) { - pw.print("IOException creating ParcelFileDescriptor: "); - pw.println(e); - } + DeviceConfig.dump(pw, /* prefix= */ " ", args); } IContentProvider iprovider = mProvider.getIContentProvider(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags index 7eff16b0def4..0367fe0dab01 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags +++ b/packages/SettingsProvider/src/com/android/providers/settings/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.providers.settings; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 9ab853ff4964..326bff448193 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -22,6 +22,7 @@ import android.annotation.UserIdInt; import android.app.backup.BackupAgentHelper; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; +import android.app.backup.BackupRestoreEventLogger; import android.app.backup.FullBackupDataOutput; import android.content.ContentResolver; import android.content.ContentValues; @@ -82,6 +83,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.HashMap; import java.util.zip.CRC32; /** @@ -194,6 +196,22 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY = "pin_enhanced_privacy"; + // Error messages for logging metrics. + private static final String ERROR_COULD_NOT_READ_FROM_CURSOR = + "could_not_read_from_cursor"; + private static final String ERROR_FAILED_TO_WRITE_ENTITY = + "failed_to_write_entity"; + private static final String ERROR_COULD_NOT_READ_ENTITY = + "could_not_read_entity"; + private static final String ERROR_SKIPPED_BY_SYSTEM = "skipped_by_system"; + private static final String ERROR_SKIPPED_BY_BLOCKLIST = + "skipped_by_dynamic_blocklist"; + private static final String ERROR_SKIPPED_PRESERVED = "skipped_preserved"; + private static final String ERROR_SKIPPED_DUE_TO_LARGE_SCREEN = + "skipped_due_to_large_screen"; + private static final String ERROR_DID_NOT_PASS_VALIDATION = "did_not_pass_validation"; + + // Name of the temporary file we use during full backup/restore. This is // stored in the full-backup tarfile as well, so should not be changed. private static final String STAGE_FILE = "flattened-data"; @@ -224,6 +242,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { // The font_scale default value for this device. private float mDefaultFontScale; + @Nullable private BackupRestoreEventLogger mBackupRestoreEventLogger; + @VisibleForTesting boolean areAgentMetricsEnabled = false; + @VisibleForTesting protected Map<String, Integer> numberOfSettingsPerKey; + @Override public void onCreate() { if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); @@ -232,6 +254,11 @@ public class SettingsBackupAgent extends BackupAgentHelper { .getStringArray(R.array.entryvalues_font_size); mSettingsHelper = new SettingsHelper(this); mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); + if (com.android.server.backup.Flags.enableMetricsSettingsBackupAgents()) { + mBackupRestoreEventLogger = this.getBackupRestoreEventLogger(); + numberOfSettingsPerKey = new HashMap<>(); + areAgentMetricsEnabled = true; + } super.onCreate(); } @@ -356,7 +383,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal, movedToSecure, /* movedToSystem= */ null, R.array.restore_blocked_system_settings, dynamicBlockList, - preservedSystemSettings); + preservedSystemSettings, KEY_SYSTEM); mSettingsHelper.applyAudioSettings(); break; @@ -364,13 +391,13 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, /* movedToSecure= */ null, movedToSystem, R.array.restore_blocked_secure_settings, dynamicBlockList, - preservedSecureSettings); + preservedSecureSettings, KEY_SECURE); break; case KEY_GLOBAL : restoreSettings(data, Settings.Global.CONTENT_URI, /* movedToGlobal= */ null, movedToSecure, movedToSystem, R.array.restore_blocked_global_settings, - dynamicBlockList, preservedGlobalSettings); + dynamicBlockList, preservedGlobalSettings, KEY_GLOBAL); break; case KEY_WIFI_SUPPLICANT : @@ -489,7 +516,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal, movedToSecure, /* movedToSystem= */ null, R.array.restore_blocked_system_settings, Collections.emptySet(), - Collections.emptySet()); + Collections.emptySet(), KEY_SYSTEM); // secure settings nBytes = in.readInt(); @@ -499,7 +526,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, /* movedToSecure= */ null, movedToSystem, R.array.restore_blocked_secure_settings, Collections.emptySet(), - Collections.emptySet()); + Collections.emptySet(), KEY_SECURE); // Global only if sufficiently new if (version >= FULL_BACKUP_ADDED_GLOBAL) { @@ -510,7 +537,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, /* movedToGlobal= */ null, movedToSecure, movedToSystem, R.array.restore_blocked_global_settings, Collections.emptySet(), - Collections.emptySet()); + Collections.emptySet(), KEY_GLOBAL); } // locale @@ -654,23 +681,41 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (oldChecksum == newChecksum) { return oldChecksum; } + writeDataForKey(key, data, output); + return newChecksum; + } + + @VisibleForTesting + void writeDataForKey(String key, byte[] data, BackupDataOutput output) { + boolean shouldLogMetrics = + areAgentMetricsEnabled && numberOfSettingsPerKey.containsKey(key); try { if (DEBUG_BACKUP) { Log.v(TAG, "Writing entity " + key + " of size " + data.length); } output.writeEntityHeader(key, data.length); output.writeEntityData(data, data.length); + if (shouldLogMetrics) { + mBackupRestoreEventLogger + .logItemsBackedUp(key, numberOfSettingsPerKey.get(key)); + } } catch (IOException ioe) { // Bail + if (shouldLogMetrics) { + mBackupRestoreEventLogger + .logItemsBackupFailed( + key, + numberOfSettingsPerKey.get(key), + ERROR_FAILED_TO_WRITE_ENTITY); + } } - return newChecksum; } private byte[] getSystemSettings() { Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null, null, null); try { - return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP); + return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP, KEY_SYSTEM); } finally { cursor.close(); } @@ -680,7 +725,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null); try { - return extractRelevantValues(cursor, SecureSettings.SETTINGS_TO_BACKUP); + return extractRelevantValues(cursor, SecureSettings.SETTINGS_TO_BACKUP, KEY_SECURE); } finally { cursor.close(); } @@ -690,7 +735,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null, null, null); try { - return extractRelevantValues(cursor, getGlobalSettingsToBackup()); + return extractRelevantValues(cursor, getGlobalSettingsToBackup(), KEY_GLOBAL); } finally { cursor.close(); } @@ -773,7 +818,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { return baos.toByteArray(); } - private void restoreSettings( + @VisibleForTesting + void restoreSettings( BackupDataInput data, Uri contentUri, Set<String> movedToGlobal, @@ -781,12 +827,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, - Set<String> settingsToPreserve) { + Set<String> settingsToPreserve, + String settingsKey) { byte[] settings = new byte[data.getDataSize()]; try { data.readEntityData(settings, 0, settings.length); } catch (IOException ioe) { Log.e(TAG, "Couldn't read entity data"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + settingsKey, /* count= */ 1, ERROR_COULD_NOT_READ_ENTITY); + } return; } restoreSettings( @@ -798,7 +849,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { movedToSystem, blockedSettingsArrayId, dynamicBlockList, - settingsToPreserve); + settingsToPreserve, + settingsKey); } private void restoreSettings( @@ -810,7 +862,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, - Set<String> settingsToPreserve) { + Set<String> settingsToPreserve, + String settingsKey) { restoreSettings( settings, 0, @@ -821,7 +874,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { movedToSystem, blockedSettingsArrayId, dynamicBlockList, - settingsToPreserve); + settingsToPreserve, + settingsKey); } @VisibleForTesting @@ -835,12 +889,13 @@ public class SettingsBackupAgent extends BackupAgentHelper { Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, - Set<String> settingsToPreserve) { + Set<String> settingsToPreserve, + String settingsKey) { if (DEBUG) { Log.i(TAG, "restoreSettings: " + contentUri); } - SettingsBackupWhitelist whitelist = getBackupWhitelist(contentUri); + SettingsBackupAllowlist allowlist = getBackupAllowlist(contentUri); // Restore only the white list data. final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); @@ -850,7 +905,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { Set<String> blockedSettings = getBlockedSettings(blockedSettingsArrayId); - for (String key : whitelist.mSettingsWhitelist) { + int restoredSettingsCount = 0; + for (String key : allowlist.mSettingsAllowlist) { boolean isBlockedBySystem = blockedSettings != null && blockedSettings.contains(key); if (isBlockedBySystem || isBlockedByDynamicList(dynamicBlockList, contentUri, key)) { Log.i( @@ -860,6 +916,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { + " removed from restore by " + (isBlockedBySystem ? "system" : "dynamic") + " block list"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + settingsKey, + /* count= */ 1, + isBlockedBySystem ? ERROR_SKIPPED_BY_SYSTEM : ERROR_SKIPPED_BY_BLOCKLIST); + } continue; } @@ -870,12 +932,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (isSettingPreserved && !Settings.Secure.NAVIGATION_MODE.equals(key)) { Log.i(TAG, "Skipping restore for setting " + key + " as it is marked as " + "preserved"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + settingsKey, /* count= */ 1, ERROR_SKIPPED_PRESERVED); + } continue; } if (LargeScreenSettings.doNotRestoreIfLargeScreenSetting(key, getBaseContext())) { Log.i(TAG, "Skipping restore for setting " + key + " as the target device " + "is a large screen (i.e tablet or foldable in unfolded state)"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + settingsKey, /* count= */ 1, ERROR_SKIPPED_DUE_TO_LARGE_SCREEN); + } continue; } @@ -912,19 +982,34 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // only restore the settings that have valid values - if (!isValidSettingValue(key, value, whitelist.mSettingsValidators)) { + if (!isValidSettingValue(key, value, allowlist.mSettingsValidators)) { Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass" + " validation, value: " + value); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + settingsKey, /* count= */ 1, ERROR_DID_NOT_PASS_VALIDATION); + } continue; } final Uri destination; + // If the destination changes, we need to update the key used as datatype for metrics. + String finalSettingsKey = settingsKey; if (movedToGlobal != null && movedToGlobal.contains(key)) { destination = Settings.Global.CONTENT_URI; + if (areAgentMetricsEnabled) { + finalSettingsKey = KEY_GLOBAL; + } } else if (movedToSecure != null && movedToSecure.contains(key)) { destination = Settings.Secure.CONTENT_URI; + if (areAgentMetricsEnabled) { + finalSettingsKey = KEY_SECURE; + } } else if (movedToSystem != null && movedToSystem.contains(key)) { destination = Settings.System.CONTENT_URI; + if (areAgentMetricsEnabled) { + finalSettingsKey = KEY_SYSTEM; + } } else { destination = contentUri; } @@ -942,6 +1027,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { if (isSettingPreserved) { Log.i(TAG, "Skipping restore for setting navigation_mode " + "as it is marked as preserved"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + finalSettingsKey, /* count= */ 1, ERROR_SKIPPED_PRESERVED); + } continue; } } @@ -961,12 +1050,16 @@ public class SettingsBackupAgent extends BackupAgentHelper { Log.d(TAG, "Restored font scale from: " + toRestore + " to " + value); } - + // TODO(b/379861078): Log metrics inside this method. settingsHelper.restoreValue(this, cr, contentValues, destination, key, value, mRestoredFromSdkInt); Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestored(finalSettingsKey, /* count= */ 1); + } } + } @@ -996,29 +1089,29 @@ public class SettingsBackupAgent extends BackupAgentHelper { } @VisibleForTesting - SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) { + SettingsBackupAllowlist getBackupAllowlist(Uri contentUri) { // Figure out the white list and redirects to the global table. We restore anything // in either the backup allowlist or the legacy-restore allowlist for this table. - String[] whitelist; + String[] allowlist; Map<String, Validator> validators = null; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { - whitelist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP, + allowlist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP, Settings.Secure.LEGACY_RESTORE_SETTINGS, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); validators = SecureSettingsValidators.VALIDATORS; } else if (contentUri.equals(Settings.System.CONTENT_URI)) { - whitelist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP, + allowlist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP, Settings.System.LEGACY_RESTORE_SETTINGS); validators = SystemSettingsValidators.VALIDATORS; } else if (contentUri.equals(Settings.Global.CONTENT_URI)) { - whitelist = ArrayUtils.concat(String.class, getGlobalSettingsToBackup(), + allowlist = ArrayUtils.concat(String.class, getGlobalSettingsToBackup(), Settings.Global.LEGACY_RESTORE_SETTINGS); validators = GlobalSettingsValidators.VALIDATORS; } else { throw new IllegalArgumentException("Unknown URI: " + contentUri); } - return new SettingsBackupWhitelist(whitelist, validators); + return new SettingsBackupAllowlist(allowlist, validators); } private String[] getGlobalSettingsToBackup() { @@ -1118,11 +1211,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { * * @param cursor A cursor with settings data. * @param settings The settings to extract. + * @param settingsKey The key of the settings to extract (eg system). * @return The byte array of extracted values. */ - private byte[] extractRelevantValues(Cursor cursor, String[] settings) { + private byte[] extractRelevantValues( + Cursor cursor, String[] settings, String settingsKey) { if (!cursor.moveToFirst()) { Log.e(TAG, "Couldn't read from the cursor"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger + .logItemsBackupFailed( + settingsKey, + settings.length, + ERROR_COULD_NOT_READ_FROM_CURSOR); + } return new byte[0]; } @@ -1181,6 +1283,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { } } + if (areAgentMetricsEnabled) { + numberOfSettingsPerKey.put(settingsKey, backedUpSettingIndex); + } + // Aggregate the result. byte[] result = new byte[totalSize]; int pos = 0; @@ -1364,7 +1470,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { getContentResolver() .query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) { return extractRelevantValues( - cursor, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); + cursor, + DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP, + KEY_DEVICE_SPECIFIC_CONFIG); } } @@ -1399,7 +1507,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { null, blockedSettingsArrayId, dynamicBlocklist, - preservedSettings); + preservedSettings, + KEY_DEVICE_SPECIFIC_CONFIG); updateWindowManagerIfNeeded(originalDensity); @@ -1597,14 +1706,14 @@ public class SettingsBackupAgent extends BackupAgentHelper { * Store the allowlist of settings to be backed up and validators for them. */ @VisibleForTesting - static class SettingsBackupWhitelist { - final String[] mSettingsWhitelist; + static class SettingsBackupAllowlist { + final String[] mSettingsAllowlist; final Map<String, Validator> mSettingsValidators; - SettingsBackupWhitelist(String[] settingsWhitelist, + SettingsBackupAllowlist(String[] settingsAllowlist, Map<String, Validator> settingsValidators) { - mSettingsWhitelist = settingsWhitelist; + mSettingsAllowlist = settingsAllowlist; mSettingsValidators = settingsValidators; } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 7aed61533aac..5cd534e62ea9 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -171,7 +171,6 @@ final class SettingsState { private static final List<String> sAconfigTextProtoFilesOnDevice = List.of( "/system/etc/aconfig_flags.pb", - "/system_ext/etc/aconfig_flags.pb", "/product/etc/aconfig_flags.pb", "/vendor/etc/aconfig_flags.pb"); diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java index 3a39150523ac..350c149f40de 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java @@ -17,11 +17,23 @@ package com.android.providers.settings; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertArrayEquals; - +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import android.app.backup.BackupAnnotations.BackupDestination; +import android.app.backup.BackupAnnotations.OperationType; +import android.app.backup.BackupDataInput; +import android.app.backup.BackupDataOutput; +import android.app.backup.BackupRestoreEventLogger; +import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -32,7 +44,10 @@ import android.database.MatrixCursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.settings.validators.SettingsValidators; import android.provider.settings.validators.Validator; @@ -43,9 +58,14 @@ import androidx.test.runner.AndroidJUnit4; import com.android.window.flags.Flags; +import java.util.List; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -54,12 +74,14 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; + /** * Tests for the SettingsHelperTest * Usage: atest SettingsProviderTest:SettingsBackupAgentTest @@ -73,6 +95,17 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { private static final Map<String, String> DEVICE_SPECIFIC_TEST_VALUES = new HashMap<>(); private static final Map<String, String> TEST_VALUES = new HashMap<>(); private static final Map<String, Validator> TEST_VALUES_VALIDATORS = new HashMap<>(); + private static final String TEST_KEY = "test_key"; + private static final String TEST_VALUE = "test_value"; + private static final String ERROR_COULD_NOT_READ_ENTITY = "could_not_read_entity"; + private static final String ERROR_SKIPPED_BY_SYSTEM = "skipped_by_system"; + private static final String ERROR_SKIPPED_BY_BLOCKLIST = + "skipped_by_dynamic_blocklist"; + private static final String ERROR_SKIPPED_PRESERVED = "skipped_preserved"; + private static final String ERROR_DID_NOT_PASS_VALIDATION = "did_not_pass_validation"; + private static final String KEY_SYSTEM = "system"; + private static final String KEY_SECURE = "secure"; + private static final String KEY_GLOBAL = "global"; static { DEVICE_SPECIFIC_TEST_VALUES.put(Settings.Secure.DISPLAY_DENSITY_FORCED, @@ -86,6 +119,14 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { TEST_VALUES_VALIDATORS.put(PRESERVED_TEST_SETTING, SettingsValidators.ANY_STRING_VALIDATOR); } + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock private BackupDataInput mBackupDataInput; + @Mock private BackupDataOutput mBackupDataOutput; + private TestFriendlySettingsBackupAgent mAgentUnderTest; private Context mContext; @@ -203,19 +244,32 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Test public void testOnRestore_preservedSettingsAreNotRestored() { - SettingsBackupAgent.SettingsBackupWhitelist whitelist = - new SettingsBackupAgent.SettingsBackupWhitelist( + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( new String[] { OVERRIDDEN_TEST_SETTING, PRESERVED_TEST_SETTING }, TEST_VALUES_VALIDATORS); - mAgentUnderTest.setSettingsWhitelist(whitelist); + mAgentUnderTest.setSettingsAllowlist(allowlist); mAgentUnderTest.setBlockedSettings(); TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); mAgentUnderTest.mSettingsHelper = settingsHelper; byte[] backupData = generateBackupData(TEST_VALUES); - mAgentUnderTest.restoreSettings(backupData, /* pos */ 0, backupData.length, TEST_URI, - null, null, null, /* blockedSettingsArrayId */ 0, Collections.emptySet(), - new HashSet<>(Collections.singletonList(SettingsBackupAgent.getQualifiedKeyForSetting(PRESERVED_TEST_SETTING, TEST_URI)))); + mAgentUnderTest.restoreSettings( + backupData, + /* pos */ 0, + backupData.length, + TEST_URI, + null, + null, + null, + /* blockedSettingsArrayId */ 0, + Collections.emptySet(), + new HashSet<>(Collections + .singletonList( + SettingsBackupAgent + .getQualifiedKeyForSetting( + PRESERVED_TEST_SETTING, TEST_URI))), + TEST_KEY); assertTrue(settingsHelper.mWrittenValues.containsKey(OVERRIDDEN_TEST_SETTING)); assertFalse(settingsHelper.mWrittenValues.containsKey(PRESERVED_TEST_SETTING)); @@ -262,6 +316,486 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { assertEquals("1.5", testedMethod.apply("1.8")); } + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void onCreate_metricsFlagIsDisabled_areAgentMetricsEnabledIsFalse() { + mAgentUnderTest.onCreate(); + + assertFalse(mAgentUnderTest.areAgentMetricsEnabled); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void onCreate_flagIsEnabled_areAgentMetricsEnabledIsTrue() { + mAgentUnderTest.onCreate(); + + assertTrue(mAgentUnderTest.areAgentMetricsEnabled); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void writeDataForKey_metricsFlagIsEnabled_numberOfSettingsPerKeyContainsKey_dataWriteSucceeds_logsSuccessMetrics() + throws IOException { + when(mBackupDataOutput.writeEntityHeader(anyString(), anyInt())).thenReturn(0); + when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt())).thenReturn(0); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + mAgentUnderTest.setNumberOfSettingsPerKey(TEST_KEY, 1); + + mAgentUnderTest.writeDataForKey( + TEST_KEY, TEST_VALUE.getBytes(), mBackupDataOutput); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void writeDataForKey_metricsFlagIsEnabled_numberOfSettingsPerKeyContainsKey_writeEntityHeaderFails_logsFailureMetrics() + throws IOException { + when(mBackupDataOutput.writeEntityHeader(anyString(), anyInt())).thenThrow(new IOException()); + when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt())).thenReturn(0); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + mAgentUnderTest.setNumberOfSettingsPerKey(TEST_KEY, 1); + + mAgentUnderTest.writeDataForKey( + TEST_KEY, TEST_VALUE.getBytes(), mBackupDataOutput); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void writeDataForKey_metricsFlagIsEnabled_numberOfSettingsPerKeyContainsKey_writeEntityDataFails_logsFailureMetrics() + throws IOException { + when(mBackupDataOutput.writeEntityHeader(anyString(), anyInt())).thenReturn(0); + when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt())).thenThrow(new IOException()); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + mAgentUnderTest.setNumberOfSettingsPerKey(TEST_KEY, 1); + + mAgentUnderTest.writeDataForKey( + TEST_KEY, TEST_VALUE.getBytes(), mBackupDataOutput); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void writeDataForKey_metricsFlagIsDisabled_doesNotLogMetrics() + throws IOException { + when(mBackupDataOutput.writeEntityHeader(anyString(), anyInt())).thenReturn(0); + when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt())).thenReturn(0); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + mAgentUnderTest.setNumberOfSettingsPerKey(TEST_KEY, 1); + + mAgentUnderTest.writeDataForKey( + TEST_KEY, TEST_VALUE.getBytes(), mBackupDataOutput); + + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void writeDataForKey_metricsFlagIsEnabled_numberOfSettingsPerKeyDoesNotContainKey_doesNotLogMetrics() + throws IOException { + when(mBackupDataOutput.writeEntityHeader(anyString(), anyInt())).thenReturn(0); + when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt())).thenReturn(0); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + + mAgentUnderTest.writeDataForKey( + TEST_KEY, TEST_VALUE.getBytes(), mBackupDataOutput); + + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_agentMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreDisabled_agentMetricsAreNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNull(loggingResult); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_readEntityDataFails_failureIsLogged() + throws IOException { + when(mBackupDataInput.readEntityData(any(byte[].class), anyInt(), anyInt())) + .thenThrow(new IOException()); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + + mAgentUnderTest.restoreSettings( + mBackupDataInput, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_COULD_NOT_READ_ENTITY)); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreDisabled_readEntityDataFails_failureIsNotLogged() + throws IOException { + when(mBackupDataInput.readEntityData(any(byte[].class), anyInt(), anyInt())) + .thenThrow(new IOException()); + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + + mAgentUnderTest.restoreSettings( + mBackupDataInput, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsSkippedBySystem_failureIsLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + String[] settingBlockedBySystem = new String[] {OVERRIDDEN_TEST_SETTING}; + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + settingBlockedBySystem, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(settingBlockedBySystem); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_SKIPPED_BY_SYSTEM)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsSkippedByBlockList_failureIsLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + Set<String> dynamicBlockList = + Set.of(Uri.withAppendedPath(TEST_URI, OVERRIDDEN_TEST_SETTING).toString()); + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + dynamicBlockList, + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_SKIPPED_BY_BLOCKLIST)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsPreserved_failureIsLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + Set<String> preservedSettings = + Set.of(Uri.withAppendedPath(TEST_URI, OVERRIDDEN_TEST_SETTING).toString()); + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList = */ Collections.emptySet(), + preservedSettings, + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_SKIPPED_PRESERVED)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsNotValid_failureIsLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + /* settingsValidators= */ null); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList = */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + assertTrue(loggingResult.getErrors().containsKey(ERROR_DID_NOT_PASS_VALIDATION)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToGlobal_agentMetricsAreLoggedWithGlobalKey() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* movedToSecure= */ null, + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_GLOBAL, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToSecure_agentMetricsAreLoggedWithSecureKey() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* movedToSystem= */ null, + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SECURE, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreSettings_agentMetricsAreEnabled_settingIsMarkedAsMovedToSystem_agentMetricsAreLoggedWithSystemKey() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + SettingsBackupAgent.SettingsBackupAllowlist allowlist = + new SettingsBackupAgent.SettingsBackupAllowlist( + new String[] {OVERRIDDEN_TEST_SETTING}, + TEST_VALUES_VALIDATORS); + mAgentUnderTest.setSettingsAllowlist(allowlist); + mAgentUnderTest.setBlockedSettings(); + TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext); + mAgentUnderTest.mSettingsHelper = settingsHelper; + + byte[] backupData = generateBackupData(TEST_VALUES); + mAgentUnderTest + .restoreSettings( + backupData, + /* pos= */ 0, + backupData.length, + TEST_URI, + /* movedToGlobal= */ null, + /* movedToSecure= */ null, + /* movedToSystem= */ Set.of(OVERRIDDEN_TEST_SETTING), + /* blockedSettingsArrayId= */ 0, + /* dynamicBlockList= */ Collections.emptySet(), + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SYSTEM, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + assertNull(getLoggingResultForDatatype(TEST_KEY, mAgentUnderTest)); + } + private byte[] generateBackupData(Map<String, String> keyValueData) { int totalBytes = 0; for (String key : keyValueData.keySet()) { @@ -293,7 +827,8 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { null, R.array.restore_blocked_global_settings, /* dynamicBlockList= */ Collections.emptySet(), - /* settingsToPreserve= */ Collections.emptySet()); + /* settingsToPreserve= */ Collections.emptySet(), + TEST_KEY); } private byte[] generateUncorruptedHeader() throws IOException { @@ -329,6 +864,21 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { } } + private DataTypeResult getLoggingResultForDatatype( + String dataType, SettingsBackupAgent agent) { + if (agent.getBackupRestoreEventLogger() == null) { + return null; + } + List<DataTypeResult> loggingResults = + agent.getBackupRestoreEventLogger().getLoggingResults(); + for (DataTypeResult result : loggingResults) { + if (result.getDataType().equals(dataType)) { + return result; + } + } + return null; + } + private byte[] generateSingleKeyTestBackupData(String key, String value) throws IOException { try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { os.write(SettingsBackupAgent.toByteArray(key)); @@ -340,7 +890,7 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { private static class TestFriendlySettingsBackupAgent extends SettingsBackupAgent { private Boolean mForcedDeviceInfoRestoreAcceptability = null; private String[] mBlockedSettings = null; - private SettingsBackupWhitelist mSettingsWhitelist = null; + private SettingsBackupAllowlist mSettingsAllowlist = null; void setForcedDeviceInfoRestoreAcceptability(boolean value) { mForcedDeviceInfoRestoreAcceptability = value; @@ -350,8 +900,8 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { mBlockedSettings = blockedSettings; } - void setSettingsWhitelist(SettingsBackupWhitelist settingsWhitelist) { - mSettingsWhitelist = settingsWhitelist; + void setSettingsAllowlist(SettingsBackupAllowlist settingsAllowlist) { + mSettingsAllowlist = settingsAllowlist; } @Override @@ -369,12 +919,18 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { } @Override - SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) { - if (mSettingsWhitelist == null) { - return super.getBackupWhitelist(contentUri); + SettingsBackupAllowlist getBackupAllowlist(Uri contentUri) { + if (mSettingsAllowlist == null) { + return super.getBackupAllowlist(contentUri); } - return mSettingsWhitelist; + return mSettingsAllowlist; + } + + void setNumberOfSettingsPerKey(String key, int numberOfSettings) { + if (numberOfSettingsPerKey != null) { + this.numberOfSettingsPerKey.put(key, numberOfSettings); + } } } 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/Shell/res/values/defaults.xml b/packages/Shell/res/values/defaults.xml new file mode 100644 index 000000000000..b693cc826be0 --- /dev/null +++ b/packages/Shell/res/values/defaults.xml @@ -0,0 +1,5 @@ +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Default for Wear bugreport warning activity--> + <!-- DO NOT TRANSLATE --> + <string name="system_ui_wear_bugreport_warning_activity" /> +</resources>
\ No newline at end of file diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 9736831a0793..0694b6123c11 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -1365,7 +1365,11 @@ public class BugreportProgressService extends Service { */ private Intent buildWearWarningIntent() { Intent intent = new Intent(); - intent.setClassName(mContext, getPackageName() + ".WearBugreportWarningActivity"); + String systemUIPackage = mContext.getResources().getString( + com.android.internal.R.string.config_systemUi); + String wearBugreportWarningActivity = getResources() + .getString(R.string.system_ui_wear_bugreport_warning_activity); + intent.setClassName(systemUIPackage, wearBugreportWarningActivity); if (mContext.getPackageManager().resolveActivity(intent, /* flags */ 0) == null) { Log.e(TAG, "Cannot find wear bugreport warning activity"); return buildWarningIntent(mContext, /* sendIntent */ null); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 5519b5171090..11cb0703d353 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -385,6 +385,9 @@ is ready --> <uses-permission android:name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" /> + <!-- To be able to decipher default applications for certain roles in shortcut helper --> + <uses-permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS" /> + <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> 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/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index c1f786826922..ee229158decc 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1230,13 +1230,6 @@ flag { } flag { - name: "communal_hub_on_mobile" - namespace: "systemui" - description: "Brings the glanceable hub experience to mobile phones" - bug: "375689917" -} - -flag { name: "glanceable_hub_v2" namespace: "systemui" description: "Gates the refreshed glanceable hub experience that also brings the glanceable hub to mobile phones" diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java index 0317d5f095a1..d0404ec02306 100644 --- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java +++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java @@ -18,8 +18,11 @@ package com.android.systemui.animation; import android.annotation.Nullable; import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Build; import android.util.Log; import android.view.Surface; @@ -44,6 +47,9 @@ import java.util.concurrent.Executor; public class ViewUIComponent implements UIComponent { private static final String TAG = "ViewUIComponent"; private static final boolean DEBUG = Build.IS_USERDEBUG || Log.isLoggable(TAG, Log.DEBUG); + private final Path mClippingPath = new Path(); + private final Outline mClippingOutline = new Outline(); + private final OnDrawListener mOnDrawListener = this::postDraw; private final View mView; @@ -182,6 +188,17 @@ public class ViewUIComponent implements UIComponent { canvas.scale( (float) renderBounds.width() / realBounds.width(), (float) renderBounds.height() / realBounds.height()); + + if (mView.getClipToOutline()) { + mView.getOutlineProvider().getOutline(mView, mClippingOutline); + mClippingPath.reset(); + RectF rect = new RectF(0, 0, mView.getWidth(), mView.getHeight()); + final float cornerRadius = mClippingOutline.getRadius(); + mClippingPath.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW); + mClippingPath.close(); + canvas.clipPath(mClippingPath); + } + canvas.saveLayerAlpha(null, (int) (255 * mView.getAlpha())); mView.draw(canvas); canvas.restore(); diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt index 3eeaf41d874a..41a00f5237f7 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt @@ -873,6 +873,9 @@ constructor( ) { // Raise closing task to "above" layer so it isn't covered. t.setLayer(target.leash, aboveLayers - i) + } else if (TransitionUtil.isOpeningType(change.mode)) { + // Put into the "below" layer space. + t.setLayer(target.leash, belowLayers - i) } } else if (TransitionInfo.isIndependent(change, info)) { // Root tasks @@ -1153,7 +1156,7 @@ constructor( // If a [controller.windowAnimatorState] exists, treat this like a takeover. takeOverAnimationInternal( window, - startWindowStates = null, + startWindowState = null, startTransaction = null, callback, ) @@ -1168,22 +1171,23 @@ constructor( callback: IRemoteAnimationFinishedCallback?, ) { val window = setUpAnimation(apps, callback) ?: return - takeOverAnimationInternal(window, startWindowStates, startTransaction, callback) + val startWindowState = startWindowStates[apps!!.indexOf(window)] + takeOverAnimationInternal(window, startWindowState, startTransaction, callback) } private fun takeOverAnimationInternal( window: RemoteAnimationTarget, - startWindowStates: Array<WindowAnimationState>?, + startWindowState: WindowAnimationState?, startTransaction: SurfaceControl.Transaction?, callback: IRemoteAnimationFinishedCallback?, ) { val useSpring = - !controller.isLaunching && startWindowStates != null && startTransaction != null + !controller.isLaunching && startWindowState != null && startTransaction != null startAnimation( window, navigationBar = null, useSpring, - startWindowStates, + startWindowState, startTransaction, callback, ) @@ -1293,7 +1297,7 @@ constructor( window: RemoteAnimationTarget, navigationBar: RemoteAnimationTarget? = null, useSpring: Boolean = false, - startingWindowStates: Array<WindowAnimationState>? = null, + startingWindowState: WindowAnimationState? = null, startTransaction: SurfaceControl.Transaction? = null, iCallback: IRemoteAnimationFinishedCallback? = null, ) { @@ -1339,6 +1343,7 @@ constructor( val isExpandingFullyAbove = transitionAnimator.isExpandingFullyAbove(controller.transitionContainer, endState) + val windowState = startingWindowState ?: controller.windowAnimatorState // We animate the opening window and delegate the view expansion to [this.controller]. val delegate = this.controller @@ -1361,18 +1366,6 @@ constructor( } } - // The states are sorted matching the changes inside the transition info. - // Using this info, the RemoteAnimationTargets are created, with their - // prefixOrderIndex fields in reverse order to that of changes. To extract - // the right state, we need to invert again. - val windowState = - if (startingWindowStates != null) { - startingWindowStates[ - startingWindowStates.size - window.prefixOrderIndex] - } else { - controller.windowAnimatorState - } - // TODO(b/323863002): use the timestamp and velocity to update the initial // position. val bounds = windowState?.bounds @@ -1461,12 +1454,6 @@ constructor( delegate.onTransitionAnimationProgress(state, progress, linearProgress) } } - val windowState = - if (startingWindowStates != null) { - startingWindowStates[startingWindowStates.size - window.prefixOrderIndex] - } else { - controller.windowAnimatorState - } val velocityPxPerS = if (longLivedReturnAnimationsEnabled() && windowState?.velocityPxPerMs != null) { val xVelocityPxPerS = windowState.velocityPxPerMs.x * 1000 @@ -1485,6 +1472,7 @@ constructor( fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow, drawHole = !controller.isBelowAnimatingWindow, startVelocity = velocityPxPerS, + startFrameTime = windowState?.timestamp ?: -1, ) } 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/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt index e2bc4095e1b5..4e889e946a5f 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt @@ -27,6 +27,8 @@ import android.graphics.drawable.GradientDrawable import android.util.FloatProperty import android.util.Log import android.util.MathUtils +import android.util.TimeUtils +import android.view.Choreographer import android.view.View import android.view.ViewGroup import android.view.ViewGroupOverlay @@ -366,6 +368,7 @@ class TransitionAnimator( @get:VisibleForTesting val springY: SpringAnimation, @get:VisibleForTesting val springScale: SpringAnimation, private val springState: SpringState, + private val startFrameTime: Long, private val onAnimationStart: Runnable, ) : Animation { @get:VisibleForTesting @@ -374,6 +377,42 @@ class TransitionAnimator( override fun start() { onAnimationStart.run() + + // If no start frame time is provided, we start the springs normally. + if (startFrameTime < 0) { + startSprings() + return + } + + // This function is not guaranteed to be called inside a frame. We try to access the + // frame time immediately, but if we're not inside a frame this will throw an exception. + // We must then post a callback to be run at the beginning of the next frame. + try { + initAndStartSprings(Choreographer.getInstance().frameTime) + } catch (_: IllegalStateException) { + Choreographer.getInstance().postFrameCallback { frameTimeNanos -> + initAndStartSprings(frameTimeNanos / TimeUtils.NANOS_PER_MS) + } + } + } + + private fun initAndStartSprings(frameTime: Long) { + // Initialize the spring as if it had started at the time that its start state + // was created. + springX.doAnimationFrame(startFrameTime) + springY.doAnimationFrame(startFrameTime) + springScale.doAnimationFrame(startFrameTime) + // Move the spring time forward to the current frame, so it updates its internal state + // following the initial momentum over the elapsed time. + springX.doAnimationFrame(frameTime) + springY.doAnimationFrame(frameTime) + springScale.doAnimationFrame(frameTime) + // Actually start the spring. We do this after the previous calls because the framework + // doesn't like it when you call doAnimationFrame() after start() with an earlier time. + startSprings() + } + + private fun startSprings() { springX.start() springY.start() springScale.start() @@ -471,7 +510,9 @@ class TransitionAnimator( * is true. * * If [startVelocity] (expressed in pixels per second) is not null, a multi-spring animation - * using it for the initial momentum will be used instead of the default interpolators. + * using it for the initial momentum will be used instead of the default interpolators. In this + * case, [startFrameTime] (if non-negative) represents the frame time at which the springs + * should be started. */ fun startAnimation( controller: Controller, @@ -480,6 +521,7 @@ class TransitionAnimator( fadeWindowBackgroundLayer: Boolean = true, drawHole: Boolean = false, startVelocity: PointF? = null, + startFrameTime: Long = -1, ): Animation { if (!controller.isLaunching) assertReturnAnimations() if (startVelocity != null) assertLongLivedReturnAnimations() @@ -502,6 +544,7 @@ class TransitionAnimator( fadeWindowBackgroundLayer, drawHole, startVelocity, + startFrameTime, ) .apply { start() } } @@ -515,6 +558,7 @@ class TransitionAnimator( fadeWindowBackgroundLayer: Boolean = true, drawHole: Boolean = false, startVelocity: PointF? = null, + startFrameTime: Long = -1, ): Animation { val transitionContainer = controller.transitionContainer val transitionContainerOverlay = transitionContainer.overlay @@ -537,6 +581,7 @@ class TransitionAnimator( startState, endState, startVelocity, + startFrameTime, windowBackgroundLayer, transitionContainer, transitionContainerOverlay, @@ -722,6 +767,7 @@ class TransitionAnimator( startState: State, endState: State, startVelocity: PointF, + startFrameTime: Long, windowBackgroundLayer: GradientDrawable, transitionContainer: View, transitionContainerOverlay: ViewGroupOverlay, @@ -912,7 +958,7 @@ class TransitionAnimator( } } - return MultiSpringAnimation(springX, springY, springScale, springState) { + return MultiSpringAnimation(springX, springY, springScale, springState, startFrameTime) { onAnimationStart( controller, isExpandingFullyAbove, diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt index 2f83d82bbec7..2a27a3033cf9 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt @@ -25,6 +25,7 @@ import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Scope import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner +import com.intellij.psi.PsiParameter import org.jetbrains.uast.UClass import org.jetbrains.uast.getContainingUFile @@ -40,14 +41,8 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { if (!isInRelevantShadePackage(node)) continue if (IGNORED_PACKAGES.contains(node.qualifiedName)) continue - // Check the any context-dependent parameter to see if it has @ShadeDisplayAware - // annotation for (parameter in constructor.parameterList.parameters) { - val shouldReport = - CONTEXT_DEPENDENT_SHADE_CLASSES.contains( - parameter.type.canonicalText - ) && !parameter.hasAnnotation(SHADE_DISPLAY_AWARE_ANNOTATION) - if (shouldReport) { + if (parameter.shouldReport()) { context.report( issue = ISSUE, scope = parameter.declarationScope, @@ -62,20 +57,35 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { companion object { private const val INJECT_ANNOTATION = "javax.inject.Inject" + private const val APPLICATION_ANNOTATION = + "com.android.systemui.dagger.qualifiers.Application" private const val SHADE_DISPLAY_AWARE_ANNOTATION = "com.android.systemui.shade.ShadeDisplayAware" + private const val MAIN_ANNOTATION = "com.android.systemui.dagger.qualifiers.Main" + + private const val CONTEXT = "android.content.Context" + private const val WINDOW_MANAGER = "android.view.WindowManager" + private const val LAYOUT_INFLATER = "android.view.LayoutInflater" + private const val RESOURCES = "android.content.res.Resources" + private const val CONFIG_STATE = "com.android.systemui.common.ui.ConfigurationState" + private const val CONFIG_CONTROLLER = + "com.android.systemui.statusbar.policy.ConfigurationController" + private const val CONFIG_INTERACTOR = + "com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor" private val CONTEXT_DEPENDENT_SHADE_CLASSES = setOf( - "android.content.Context", - "android.view.WindowManager", - "android.view.LayoutInflater", - "android.content.res.Resources", - "com.android.systemui.common.ui.ConfigurationState", - "com.android.systemui.statusbar.policy.ConfigurationController", - "com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor", + CONTEXT, + WINDOW_MANAGER, + LAYOUT_INFLATER, + RESOURCES, + CONFIG_STATE, + CONFIG_CONTROLLER, + CONFIG_INTERACTOR, ) + private val CONFIG_CLASSES = setOf(CONFIG_STATE, CONFIG_CONTROLLER, CONFIG_INTERACTOR) + private val SHADE_WINDOW_PACKAGES = listOf( "com.android.systemui.biometrics", @@ -93,6 +103,19 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { "com.android.systemui.qs.customize.TileAdapter", ) + private fun PsiParameter.shouldReport(): Boolean { + val className = type.canonicalText + + // check if the parameter is a context-dependent class relevant to shade + if (className !in CONTEXT_DEPENDENT_SHADE_CLASSES) return false + if (hasAnnotation(SHADE_DISPLAY_AWARE_ANNOTATION) || hasAnnotation(MAIN_ANNOTATION)) + return false + // check if its a @Application-annotated Context + if (className == CONTEXT && hasAnnotation(APPLICATION_ANNOTATION)) return false + + return true + } + private fun isInRelevantShadePackage(node: UClass): Boolean { val packageName = node.getContainingUFile()?.packageName if (packageName.isNullOrBlank()) return false @@ -102,15 +125,15 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { } private fun reportMsg(className: String) = - """UI elements of the shade window - |should use ShadeDisplayAware-annotated $className, as the shade might move between windows, and only - |@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so - |might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). - |If the usage of $className is not related to display specific configuration or UI, then there is - |technically no need to use the annotation, and you can annotate the class with - |@SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker") - |""" - .trimMargin() + "UI elements of the shade window should use " + + "ShadeDisplayAware-annotated $className, as the shade might move between windows, " + + "and only @ShadeDisplayAware resources are updated with the new configuration " + + "correctly. Failures to do so might result in wrong dimensions for shade window " + + "classes (e.g. using the wrong density or theme). If the usage of $className is " + + "not related to display specific configuration or UI, then there is technically " + + "no need to use the annotation, and you can annotate the class with " + + "@SuppressLint(\"ShadeDisplayAwareContextChecker\")/" + + "@Suppress(\"ShadeDisplayAwareContextChecker\")".trimMargin() @JvmField val ISSUE: Issue = diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt index 58ad363f5b57..638d7cb7ee58 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt @@ -63,6 +63,26 @@ class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() { ) .indented() + private val applicationStub: TestFile = + kotlin( + """ + package com.android.systemui.dagger.qualifiers + + @Retention(AnnotationRetention.RUNTIME) annotation class Application + """ + ) + .indented() + + private val mainStub: TestFile = + kotlin( + """ + package com.android.systemui.dagger.qualifiers + + @Retention(AnnotationRetention.RUNTIME) annotation class Main + """ + ) + .indented() + private val configStateStub: TestFile = kotlin( """ @@ -98,6 +118,8 @@ class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() { injectStub, qsContext, shadeDisplayAwareStub, + applicationStub, + mainStub, configStateStub, configControllerStub, configInteractorStub, @@ -259,6 +281,60 @@ class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() { } @Test + fun injectedConstructor_inRelevantPackage_withApplicationAnnotatedContext() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + + import javax.inject.Inject + import android.content.Context + import com.android.systemui.dagger.qualifiers.Application + + class ExampleClass + @Inject + constructor(@Application private val context: Context) + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectClean() + } + + @Test + fun injectedConstructor_inRelevantPackage_withMainAnnotatedConfigurationClass() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + + import javax.inject.Inject + import com.android.systemui.common.ui.ConfigurationState + import com.android.systemui.dagger.qualifiers.Main + + class ExampleClass + @Inject + constructor(@Main private val configState: ConfigurationState) + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectClean() + } + + @Test fun injectedConstructor_notInRelevantPackage_withRelevantParameter_withoutAnnotation() { lint() .files( @@ -363,13 +439,13 @@ class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() { } private fun errorMsgString(lineNumber: Int, className: String) = - """ - src/com/android/systemui/shade/example/ExampleClass.kt:$lineNumber: Error: UI elements of the shade window - should use ShadeDisplayAware-annotated $className, as the shade might move between windows, and only - @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so - might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). - If the usage of $className is not related to display specific configuration or UI, then there is - technically no need to use the annotation, and you can annotate the class with - @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker") - """ + "src/com/android/systemui/shade/example/ExampleClass.kt:$lineNumber: Error: UI elements of " + + "the shade window should use ShadeDisplayAware-annotated $className, as the shade " + + "might move between windows, and only @ShadeDisplayAware resources are updated with " + + "the new configuration correctly. Failures to do so might result in wrong dimensions " + + "for shade window classes (e.g. using the wrong density or theme). If the usage of " + + "$className is not related to display specific configuration or UI, then there is " + + "technically no need to use the annotation, and you can annotate the class with " + + "@SuppressLint(\"ShadeDisplayAwareContextChecker\")" + + "/@Suppress(\"ShadeDisplayAwareContextChecker\")" } 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 new file mode 100644 index 000000000000..029b9cde4da9 --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.gesture + +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown +import androidx.compose.foundation.gestures.awaitHorizontalTouchSlopOrCancellation +import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation +import androidx.compose.foundation.gestures.horizontalDrag +import androidx.compose.foundation.gestures.verticalDrag +import androidx.compose.foundation.overscroll +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScrollModifierNode +import androidx.compose.ui.input.pointer.AwaitPointerEventScope +import androidx.compose.ui.input.pointer.PointerEvent +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.PointerId +import androidx.compose.ui.input.pointer.PointerInputChange +import androidx.compose.ui.input.pointer.PointerInputScope +import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode +import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed +import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed +import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.input.pointer.util.VelocityTracker +import androidx.compose.ui.input.pointer.util.addPointerInputChange +import androidx.compose.ui.node.CompositionLocalConsumerModifierNode +import androidx.compose.ui.node.DelegatingNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.PointerInputModifierNode +import androidx.compose.ui.node.currentValueOf +import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.Velocity +import androidx.compose.ui.util.fastAny +import androidx.compose.ui.util.fastSumBy +import com.android.compose.modifiers.thenIf +import kotlin.math.sign +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.launch + +/** + * A draggable that plays nicely with the nested scroll mechanism. + * + * This can be used whenever you need a draggable inside a scrollable or a draggable that contains a + * scrollable. + */ +interface NestedDraggable { + /** + * Called when a drag is started in the given [position] (*before* dragging the touch slop) and + * in the direction given by [sign], with the given number of [pointersDown] when the touch slop + * was detected. + */ + fun onDragStarted(position: Offset, sign: Float, pointersDown: Int): Controller + + /** + * Whether this draggable should consume any scroll amount with the given [sign] coming from a + * nested scrollable. + * + * This is called whenever a nested scrollable does not consume some scroll amount. If this + * returns `true`, then [onDragStarted] will be called and this draggable will have priority and + * consume all future events during preScroll until the nested scroll is finished. + */ + fun shouldConsumeNestedScroll(sign: Float): Boolean + + interface Controller { + /** + * Drag by [delta] pixels. + * + * @return the consumed [delta]. Any non-consumed delta will be dispatched to the next + * nested scroll connection to be consumed by any composable above in the hierarchy. If + * the drag was performed on this draggable directly (instead of on a nested scrollable), + * any remaining delta will be used to overscroll this draggable. + */ + fun onDrag(delta: Float): Float + + /** + * Stop the current drag with the given [velocity]. + * + * @return the consumed [velocity]. Any non-consumed velocity will be dispatched to the next + * nested scroll connection to be consumed by any composable above in the hierarchy. If + * the drag was performed on this draggable directly (instead of on a nested scrollable), + * any remaining velocity will be used to animate the overscroll of this draggable. + */ + suspend fun onDragStopped(velocity: Float): Float + } +} + +/** + * A draggable that supports nested scrolling and overscroll effects. + * + * @see NestedDraggable + */ +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, 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, enabled) + } + + override fun update(node: NestedDraggableNode) { + node.update(draggable, orientation, overscrollEffect, enabled) + } +} + +private class NestedDraggableNode( + private var draggable: NestedDraggable, + override var orientation: Orientation, + private var overscrollEffect: OverscrollEffect?, + private var enabled: Boolean, +) : + DelegatingNode(), + PointerInputModifierNode, + NestedScrollConnection, + CompositionLocalConsumerModifierNode, + OrientationAware { + private val nestedScrollDispatcher = NestedScrollDispatcher() + private var trackDownPositionDelegate: SuspendingPointerInputModifierNode? = null + set(value) { + field?.let { undelegate(it) } + field = value?.also { delegate(it) } + } + + private var detectDragsDelegate: SuspendingPointerInputModifierNode? = null + set(value) { + field?.let { undelegate(it) } + field = value?.also { delegate(it) } + } + + /** The controller created by the nested scroll logic (and *not* the drag logic). */ + private var nestedScrollController: WrappedController? = null + set(value) { + field?.ensureOnDragStoppedIsCalled() + field = value + } + + /** + * The last pointer which was the first down since the last time all pointers were up. + * + * This is use to track the started position of a drag started on a nested scrollable. + */ + private var lastFirstDown: Offset? = null + + /** The number of pointers down. */ + private var pointersDownCount = 0 + + init { + delegate(nestedScrollModifierNode(this, nestedScrollDispatcher)) + } + + override fun onDetach() { + nestedScrollController?.ensureOnDragStoppedIsCalled() + } + + fun update( + 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( + pointerEvent: PointerEvent, + pass: PointerEventPass, + bounds: IntSize, + ) { + if (!enabled) return + + if (trackDownPositionDelegate == null) { + check(detectDragsDelegate == null) + trackDownPositionDelegate = SuspendingPointerInputModifierNode { trackDownPosition() } + detectDragsDelegate = SuspendingPointerInputModifierNode { detectDrags() } + } + + checkNotNull(trackDownPositionDelegate).onPointerEvent(pointerEvent, pass, bounds) + checkNotNull(detectDragsDelegate).onPointerEvent(pointerEvent, pass, bounds) + } + + override fun onCancelPointerInput() { + trackDownPositionDelegate?.onCancelPointerInput() + detectDragsDelegate?.onCancelPointerInput() + } + + /* + * ====================================== + * ===== Pointer input (drag) logic ===== + * ====================================== + */ + + private suspend fun PointerInputScope.detectDrags() { + // Lazily create the velocity tracker when the pointer input restarts. + val velocityTracker = VelocityTracker() + + awaitEachGesture { + val down = awaitFirstDown(requireUnconsumed = false) + check(down.position == lastFirstDown) { + "Position from detectDrags() is not the same as position in trackDownPosition()" + } + check(pointersDownCount == 1) { "pointersDownCount is equal to $pointersDownCount" } + + var overSlop = 0f + val onTouchSlopReached = { change: PointerInputChange, over: Float -> + change.consume() + overSlop = over + } + + suspend fun AwaitPointerEventScope.awaitTouchSlopOrCancellation( + pointerId: PointerId + ): PointerInputChange? { + return when (orientation) { + Orientation.Horizontal -> + awaitHorizontalTouchSlopOrCancellation(pointerId, onTouchSlopReached) + Orientation.Vertical -> + awaitVerticalTouchSlopOrCancellation(pointerId, onTouchSlopReached) + } + } + + var drag = awaitTouchSlopOrCancellation(down.id) + + // We try to pick-up the drag gesture in case the touch slop swipe was consumed by a + // nested scrollable child that disappeared. + // This was copied from http://shortn/_10L8U02IoL. + // TODO(b/380838584): Reuse detect(Horizontal|Vertical)DragGestures() instead. + while (drag == null && currentEvent.changes.fastAny { it.pressed }) { + var event: PointerEvent + do { + event = awaitPointerEvent() + } while ( + event.changes.fastAny { it.isConsumed } && event.changes.fastAny { it.pressed } + ) + + // An event was not consumed and there's still a pointer in the screen. + if (event.changes.fastAny { it.pressed }) { + // Await touch slop again, using the initial down as starting point. + // For most cases this should return immediately since we probably moved + // far enough from the initial down event. + drag = awaitTouchSlopOrCancellation(down.id) + } + } + + if (drag != null) { + velocityTracker.resetTracking() + val sign = (drag.position - down.position).toFloat().sign + check(pointersDownCount > 0) { "pointersDownCount is equal to $pointersDownCount" } + val wrappedController = + WrappedController( + coroutineScope, + draggable.onDragStarted(down.position, sign, pointersDownCount), + ) + if (overSlop != 0f) { + onDrag(wrappedController, drag, overSlop, velocityTracker) + } + + // If a drag was started, we cancel any other drag started by a nested scrollable. + // + // Note: we cancel the nested drag here *after* starting the new drag so that in the + // STL case, the cancelled drag will not change the current scene of the STL. + nestedScrollController?.ensureOnDragStoppedIsCalled() + + val isSuccessful = + try { + val onDrag = { change: PointerInputChange -> + onDrag( + wrappedController, + change, + change.positionChange().toFloat(), + velocityTracker, + ) + change.consume() + } + + when (orientation) { + Orientation.Horizontal -> horizontalDrag(drag.id, onDrag) + Orientation.Vertical -> verticalDrag(drag.id, onDrag) + } + } catch (t: Throwable) { + wrappedController.ensureOnDragStoppedIsCalled() + throw t + } + + if (isSuccessful) { + val maxVelocity = currentValueOf(LocalViewConfiguration).maximumFlingVelocity + val velocity = + velocityTracker + .calculateVelocity(Velocity(maxVelocity, maxVelocity)) + .toFloat() + onDragStopped(wrappedController, velocity) + } else { + onDragStopped(wrappedController, velocity = 0f) + } + } + } + } + + private fun onDrag( + controller: NestedDraggable.Controller, + change: PointerInputChange, + delta: Float, + velocityTracker: VelocityTracker, + ) { + velocityTracker.addPointerInputChange(change) + + scrollWithOverscroll(delta) { deltaFromOverscroll -> + scrollWithNestedScroll(deltaFromOverscroll) { deltaFromNestedScroll -> + controller.onDrag(deltaFromNestedScroll) + } + } + } + + private fun onDragStopped(controller: WrappedController, velocity: Float) { + coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { + try { + flingWithOverscroll(velocity) { velocityFromOverscroll -> + flingWithNestedScroll(velocityFromOverscroll) { velocityFromNestedScroll -> + controller.onDragStopped(velocityFromNestedScroll) + } + } + } finally { + controller.ensureOnDragStoppedIsCalled() + } + } + } + + private fun scrollWithOverscroll(delta: Float, performScroll: (Float) -> Float): Float { + val effect = overscrollEffect + return if (effect != null) { + effect + .applyToScroll(delta.toOffset(), source = NestedScrollSource.UserInput) { + performScroll(it.toFloat()).toOffset() + } + .toFloat() + } else { + performScroll(delta) + } + } + + private fun scrollWithNestedScroll(delta: Float, performScroll: (Float) -> Float): Float { + val preConsumed = + nestedScrollDispatcher + .dispatchPreScroll( + available = delta.toOffset(), + source = NestedScrollSource.UserInput, + ) + .toFloat() + val available = delta - preConsumed + val consumed = performScroll(available) + val left = available - consumed + val postConsumed = + nestedScrollDispatcher + .dispatchPostScroll( + consumed = (preConsumed + consumed).toOffset(), + available = left.toOffset(), + source = NestedScrollSource.UserInput, + ) + .toFloat() + return consumed + preConsumed + postConsumed + } + + private suspend fun flingWithOverscroll( + velocity: Float, + performFling: suspend (Float) -> Float, + ) { + val effect = overscrollEffect + if (effect != null) { + effect.applyToFling(velocity.toVelocity()) { performFling(it.toFloat()).toVelocity() } + } else { + performFling(velocity) + } + } + + private suspend fun flingWithNestedScroll( + velocity: Float, + performFling: suspend (Float) -> Float, + ): Float { + val preConsumed = nestedScrollDispatcher.dispatchPreFling(available = velocity.toVelocity()) + val available = velocity - preConsumed.toFloat() + val consumed = performFling(available) + val left = available - consumed + return nestedScrollDispatcher + .dispatchPostFling( + consumed = consumed.toVelocity() + preConsumed, + available = left.toVelocity(), + ) + .toFloat() + } + + /* + * =============================== + * ===== Nested scroll logic ===== + * =============================== + */ + + private suspend fun PointerInputScope.trackDownPosition() { + awaitEachGesture { + val down = awaitFirstDown(requireUnconsumed = false) + lastFirstDown = down.position + pointersDownCount = 1 + + do { + pointersDownCount += + awaitPointerEvent().changes.fastSumBy { change -> + when { + change.changedToDownIgnoreConsumed() -> 1 + change.changedToUpIgnoreConsumed() -> -1 + else -> 0 + } + } + } while (pointersDownCount > 0) + } + } + + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + val controller = nestedScrollController ?: return Offset.Zero + val consumed = controller.onDrag(available.toFloat()) + return consumed.toOffset() + } + + override fun onPostScroll( + consumed: Offset, + available: Offset, + source: NestedScrollSource, + ): Offset { + if (source == NestedScrollSource.SideEffect) { + check(nestedScrollController == null) + return Offset.Zero + } + + val offset = available.toFloat() + if (offset == 0f) { + return Offset.Zero + } + + val sign = offset.sign + if (nestedScrollController == null && draggable.shouldConsumeNestedScroll(sign)) { + val startedPosition = checkNotNull(lastFirstDown) { "lastFirstDown is not set" } + + // TODO(b/382665591): Replace this by check(pointersDownCount > 0). + val pointersDown = pointersDownCount.coerceAtLeast(1) + nestedScrollController = + WrappedController( + coroutineScope, + draggable.onDragStarted(startedPosition, sign, pointersDown), + ) + } + + val controller = nestedScrollController ?: return Offset.Zero + return controller.onDrag(offset).toOffset() + } + + override suspend fun onPreFling(available: Velocity): Velocity { + val controller = nestedScrollController ?: return Velocity.Zero + nestedScrollController = null + + val consumed = controller.onDragStopped(available.toFloat()) + return consumed.toVelocity() + } +} + +/** + * A controller that wraps [delegate] and can be used to ensure that [onDragStopped] is called, but + * not more than once. + */ +private class WrappedController( + private val coroutineScope: CoroutineScope, + private val delegate: NestedDraggable.Controller, +) : NestedDraggable.Controller by delegate { + private var onDragStoppedCalled = false + + override fun onDrag(delta: Float): Float { + if (onDragStoppedCalled) return 0f + return delegate.onDrag(delta) + } + + override suspend fun onDragStopped(velocity: Float): Float { + if (onDragStoppedCalled) return 0f + onDragStoppedCalled = true + return delegate.onDragStopped(velocity) + } + + fun ensureOnDragStoppedIsCalled() { + // Start with UNDISPATCHED so that onDragStopped() is always run until its first suspension + // point, even if coroutineScope is cancelled. + coroutineScope.launch(start = CoroutineStart.UNDISPATCHED) { onDragStopped(velocity = 0f) } + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/OrientationAware.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/OrientationAware.kt new file mode 100644 index 000000000000..6e91727e68e3 --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/OrientationAware.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.gesture + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.Velocity + +/** + * An interface to conveniently convert a [Float] to and from an [Offset] or a [Velocity] given an + * [orientation]. + */ +interface OrientationAware { + val orientation: Orientation + + fun Float.toOffset(): Offset { + return when (orientation) { + Orientation.Horizontal -> Offset(x = this, y = 0f) + Orientation.Vertical -> Offset(x = 0f, y = this) + } + } + + fun Float.toVelocity(): Velocity { + return when (orientation) { + Orientation.Horizontal -> Velocity(x = this, y = 0f) + Orientation.Vertical -> Velocity(x = 0f, y = this) + } + } + + fun Offset.toFloat(): Float { + return when (orientation) { + Orientation.Horizontal -> this.x + Orientation.Vertical -> this.y + } + } + + fun Velocity.toFloat(): Float { + return when (orientation) { + Orientation.Horizontal -> this.x + Orientation.Vertical -> this.y + } + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt index a499447fc367..fe3faafded6f 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/Color.kt @@ -37,4 +37,4 @@ fun colorAttr(context: Context, @AttrRes attr: Int): Color { @ColorInt val color = ta.getColor(0, 0) ta.recycle() return Color(color) -} +}
\ No newline at end of file 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 new file mode 100644 index 000000000000..735ab68bc6a6 --- /dev/null +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.gesture + +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.test.junit4.ComposeContentTestRule +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performTouchInput +import androidx.compose.ui.test.swipeDown +import androidx.compose.ui.test.swipeLeft +import androidx.compose.ui.unit.Velocity +import com.google.common.truth.Truth.assertThat +import kotlin.math.ceil +import kotlinx.coroutines.awaitCancellation +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +class NestedDraggableTest(override val orientation: Orientation) : OrientationAware { + companion object { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun orientations() = listOf(Orientation.Horizontal, Orientation.Vertical) + } + + @get:Rule val rule = createComposeRule() + + @Test + fun simpleDrag() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + assertThat(draggable.onDragCalled).isFalse() + assertThat(draggable.onDragStoppedCalled).isFalse() + + var rootCenter = Offset.Zero + rule.onRoot().performTouchInput { + rootCenter = center + down(center) + moveBy((touchSlop + 10f).toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragCalled).isTrue() + assertThat(draggable.onDragDelta).isEqualTo(10f) + assertThat(draggable.onDragStartedPosition).isEqualTo(rootCenter) + assertThat(draggable.onDragStartedSign).isEqualTo(1f) + assertThat(draggable.onDragStoppedCalled).isFalse() + + rule.onRoot().performTouchInput { moveBy(20f.toOffset()) } + + assertThat(draggable.onDragDelta).isEqualTo(30f) + assertThat(draggable.onDragStoppedCalled).isFalse() + + rule.onRoot().performTouchInput { + moveBy((-15f).toOffset()) + up() + } + + assertThat(draggable.onDragDelta).isEqualTo(15f) + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun nestedScrollable() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation) + .nestedScrollable(rememberScrollState()) + ) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + assertThat(draggable.onDragCalled).isFalse() + assertThat(draggable.onDragStoppedCalled).isFalse() + + var rootCenter = Offset.Zero + rule.onRoot().performTouchInput { + rootCenter = center + down(center) + moveBy((-touchSlop - 10f).toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragCalled).isTrue() + assertThat(draggable.onDragDelta).isEqualTo(-10f) + assertThat(draggable.onDragStartedPosition).isEqualTo(rootCenter) + assertThat(draggable.onDragStartedSign).isEqualTo(-1f) + assertThat(draggable.onDragStoppedCalled).isFalse() + + rule.onRoot().performTouchInput { moveBy((-20f).toOffset()) } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragCalled).isTrue() + assertThat(draggable.onDragDelta).isEqualTo(-30f) + assertThat(draggable.onDragStoppedCalled).isFalse() + + rule.onRoot().performTouchInput { + moveBy(15f.toOffset()) + up() + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragCalled).isTrue() + assertThat(draggable.onDragDelta).isEqualTo(-15f) + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun onDragStoppedIsCalledWhenDraggableIsUpdatedAndReset() { + val draggable = TestDraggable() + var orientation by mutableStateOf(orientation) + val touchSlop = + rule.setContentWithTouchSlop { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy(touchSlop.toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + orientation = + when (orientation) { + Orientation.Horizontal -> Orientation.Vertical + Orientation.Vertical -> Orientation.Horizontal + } + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun onDragStoppedIsCalledWhenDraggableIsUpdatedAndReset_nestedScroll() { + val draggable = TestDraggable() + var orientation by mutableStateOf(orientation) + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation) + .nestedScrollable(rememberScrollState()) + ) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy((touchSlop + 1f).toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + orientation = + when (orientation) { + Orientation.Horizontal -> Orientation.Vertical + Orientation.Vertical -> Orientation.Horizontal + } + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringDrag() { + val draggable = TestDraggable() + var composeContent by mutableStateOf(true) + val touchSlop = + rule.setContentWithTouchSlop { + if (composeContent) { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy(touchSlop.toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + composeContent = false + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringDrag_nestedScroll() { + val draggable = TestDraggable() + var composeContent by mutableStateOf(true) + val touchSlop = + rule.setContentWithTouchSlop { + if (composeContent) { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation) + .nestedScrollable(rememberScrollState()) + ) + } + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy((touchSlop + 1f).toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + composeContent = false + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + fun onDragStoppedIsCalledWhenDraggableIsRemovedDuringFling() { + val draggable = TestDraggable() + var composeContent by mutableStateOf(true) + var preFlingCalled = false + rule.setContent { + if (composeContent) { + Box( + Modifier.fillMaxSize() + // This nested scroll connection indefinitely suspends on pre fling, so that + // we can emulate what happens when the draggable is removed from + // composition while the pre-fling happens and onDragStopped() was not + // called yet. + .nestedScroll( + remember { + object : NestedScrollConnection { + override suspend fun onPreFling(available: Velocity): Velocity { + preFlingCalled = true + awaitCancellation() + } + } + } + ) + .nestedDraggable(draggable, orientation) + ) + } + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + // Swipe down. + rule.onRoot().performTouchInput { + when (orientation) { + Orientation.Horizontal -> swipeLeft() + Orientation.Vertical -> swipeDown() + } + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + assertThat(preFlingCalled).isTrue() + + composeContent = false + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + + @Test + @Ignore("b/303224944#comment22") + fun onDragStoppedIsCalledWhenNestedScrollableIsRemoved() { + val draggable = TestDraggable() + var composeNestedScrollable by mutableStateOf(true) + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation) + .then( + if (composeNestedScrollable) { + Modifier.nestedScrollable(rememberScrollState()) + } else { + Modifier + } + ) + ) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy((touchSlop + 1f).toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + composeNestedScrollable = false + rule.waitForIdle() + 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() + } + + @Test + fun pointersDown() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + + (1..5).forEach { nDown -> + rule.onRoot().performTouchInput { + repeat(nDown) { pointerId -> down(pointerId, center) } + + moveBy(pointerId = 0, touchSlop.toOffset()) + } + + assertThat(draggable.onDragStartedPointersDown).isEqualTo(nDown) + + rule.onRoot().performTouchInput { + repeat(nDown) { pointerId -> up(pointerId = pointerId) } + } + } + } + + @Test + fun pointersDown_nestedScroll() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation) + .nestedScrollable(rememberScrollState()) + ) + } + + (1..5).forEach { nDown -> + rule.onRoot().performTouchInput { + repeat(nDown) { pointerId -> down(pointerId, center) } + + moveBy(pointerId = 0, (touchSlop + 1f).toOffset()) + } + + assertThat(draggable.onDragStartedPointersDown).isEqualTo(nDown) + + rule.onRoot().performTouchInput { + repeat(nDown) { pointerId -> up(pointerId = pointerId) } + } + } + } + + @Test + fun pointersDown_downThenUpThenDown() { + val draggable = TestDraggable() + val touchSlop = + rule.setContentWithTouchSlop { + Box(Modifier.fillMaxSize().nestedDraggable(draggable, orientation)) + } + + val slopThird = ceil(touchSlop / 3f).toOffset() + rule.onRoot().performTouchInput { + repeat(5) { down(pointerId = it, center) } // + 5 + moveBy(pointerId = 0, slopThird) + + listOf(2, 3).forEach { up(pointerId = it) } // - 2 + moveBy(pointerId = 0, slopThird) + + listOf(5, 6, 7).forEach { down(pointerId = it, center) } // + 3 + moveBy(pointerId = 0, slopThird) + } + + assertThat(draggable.onDragStartedPointersDown).isEqualTo(6) + } + + private fun ComposeContentTestRule.setContentWithTouchSlop( + content: @Composable () -> Unit + ): Float { + var touchSlop = 0f + setContent { + touchSlop = LocalViewConfiguration.current.touchSlop + content() + } + return touchSlop + } + + private fun Modifier.nestedScrollable(scrollState: ScrollState): Modifier { + return when (orientation) { + Orientation.Vertical -> verticalScroll(scrollState) + Orientation.Horizontal -> horizontalScroll(scrollState) + } + } + + private class TestDraggable( + private val onDragStarted: (Offset, Float) -> Unit = { _, _ -> }, + private val onDrag: (Float) -> Float = { it }, + private val onDragStopped: suspend (Float) -> Float = { it }, + private val shouldConsumeNestedScroll: (Float) -> Boolean = { true }, + ) : NestedDraggable { + var onDragStartedCalled = false + var onDragCalled = false + var onDragStoppedCalled = false + + var onDragStartedPosition = Offset.Zero + var onDragStartedSign = 0f + var onDragStartedPointersDown = 0 + var onDragDelta = 0f + + override fun onDragStarted( + position: Offset, + sign: Float, + pointersDown: Int, + ): NestedDraggable.Controller { + onDragStartedCalled = true + onDragStartedPosition = position + onDragStartedSign = sign + onDragStartedPointersDown = pointersDown + onDragDelta = 0f + + onDragStarted.invoke(position, sign) + return object : NestedDraggable.Controller { + override fun onDrag(delta: Float): Float { + onDragCalled = true + onDragDelta += delta + return onDrag.invoke(delta) + } + + override suspend fun onDragStopped(velocity: Float): Float { + onDragStoppedCalled = true + return onDragStopped.invoke(velocity) + } + } + } + + override fun shouldConsumeNestedScroll(sign: Float): Boolean { + return shouldConsumeNestedScroll.invoke(sign) + } + } +} diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt index 737853b88f7a..96989a2df2f0 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt @@ -16,8 +16,8 @@ package com.android.compose.theme +import android.annotation.ColorRes import android.content.Context -import androidx.annotation.AttrRes import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -70,118 +70,118 @@ class PlatformThemeTest { val colorValues = mutableListOf<ColorValue>() fun onLaunch(colorScheme: ColorScheme, context: Context) { - fun addValue(name: String, materialValue: Color, @AttrRes attr: Int) { - colorValues.add(ColorValue(name, materialValue, colorAttr(context, attr))) + fun addValue(name: String, materialValue: Color, @ColorRes color: Int) { + colorValues.add(ColorValue(name, materialValue, Color(context.getColor(color)))) } - addValue("primary", colorScheme.primary, R.attr.materialColorPrimary) - addValue("onPrimary", colorScheme.onPrimary, R.attr.materialColorOnPrimary) + addValue("primary", colorScheme.primary, R.color.materialColorPrimary) + addValue("onPrimary", colorScheme.onPrimary, R.color.materialColorOnPrimary) addValue( "primaryContainer", colorScheme.primaryContainer, - R.attr.materialColorPrimaryContainer, + R.color.materialColorPrimaryContainer, ) addValue( "onPrimaryContainer", colorScheme.onPrimaryContainer, - R.attr.materialColorOnPrimaryContainer, + R.color.materialColorOnPrimaryContainer, ) addValue( "inversePrimary", colorScheme.inversePrimary, - R.attr.materialColorInversePrimary, + R.color.materialColorInversePrimary, ) - addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary) - addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary) + addValue("secondary", colorScheme.secondary, R.color.materialColorSecondary) + addValue("onSecondary", colorScheme.onSecondary, R.color.materialColorOnSecondary) addValue( "secondaryContainer", colorScheme.secondaryContainer, - R.attr.materialColorSecondaryContainer, + R.color.materialColorSecondaryContainer, ) addValue( "onSecondaryContainer", colorScheme.onSecondaryContainer, - R.attr.materialColorOnSecondaryContainer, + R.color.materialColorOnSecondaryContainer, ) - addValue("tertiary", colorScheme.tertiary, R.attr.materialColorTertiary) - addValue("onTertiary", colorScheme.onTertiary, R.attr.materialColorOnTertiary) + addValue("tertiary", colorScheme.tertiary, R.color.materialColorTertiary) + addValue("onTertiary", colorScheme.onTertiary, R.color.materialColorOnTertiary) addValue( "tertiaryContainer", colorScheme.tertiaryContainer, - R.attr.materialColorTertiaryContainer, + R.color.materialColorTertiaryContainer, ) addValue( "onTertiaryContainer", colorScheme.onTertiaryContainer, - R.attr.materialColorOnTertiaryContainer, + R.color.materialColorOnTertiaryContainer, ) - addValue("onBackground", colorScheme.onBackground, R.attr.materialColorOnBackground) - addValue("surface", colorScheme.surface, R.attr.materialColorSurface) - addValue("onSurface", colorScheme.onSurface, R.attr.materialColorOnSurface) + addValue("onBackground", colorScheme.onBackground, R.color.materialColorOnBackground) + addValue("surface", colorScheme.surface, R.color.materialColorSurface) + addValue("onSurface", colorScheme.onSurface, R.color.materialColorOnSurface) addValue( "surfaceVariant", colorScheme.surfaceVariant, - R.attr.materialColorSurfaceVariant, + R.color.materialColorSurfaceVariant, ) addValue( "onSurfaceVariant", colorScheme.onSurfaceVariant, - R.attr.materialColorOnSurfaceVariant, + R.color.materialColorOnSurfaceVariant, ) addValue( "inverseSurface", colorScheme.inverseSurface, - R.attr.materialColorInverseSurface, + R.color.materialColorInverseSurface, ) addValue( "inverseOnSurface", colorScheme.inverseOnSurface, - R.attr.materialColorInverseOnSurface, + R.color.materialColorInverseOnSurface, ) - addValue("error", colorScheme.error, R.attr.materialColorError) - addValue("onError", colorScheme.onError, R.attr.materialColorOnError) + addValue("error", colorScheme.error, R.color.materialColorError) + addValue("onError", colorScheme.onError, R.color.materialColorOnError) addValue( "errorContainer", colorScheme.errorContainer, - R.attr.materialColorErrorContainer, + R.color.materialColorErrorContainer, ) addValue( "onErrorContainer", colorScheme.onErrorContainer, - R.attr.materialColorOnErrorContainer, + R.color.materialColorOnErrorContainer, ) - addValue("outline", colorScheme.outline, R.attr.materialColorOutline) + addValue("outline", colorScheme.outline, R.color.materialColorOutline) addValue( "outlineVariant", colorScheme.outlineVariant, - R.attr.materialColorOutlineVariant, + R.color.materialColorOutlineVariant, ) - addValue("surfaceBright", colorScheme.surfaceBright, R.attr.materialColorSurfaceBright) - addValue("surfaceDim", colorScheme.surfaceDim, R.attr.materialColorSurfaceDim) + addValue("surfaceBright", colorScheme.surfaceBright, R.color.materialColorSurfaceBright) + addValue("surfaceDim", colorScheme.surfaceDim, R.color.materialColorSurfaceDim) addValue( "surfaceContainer", colorScheme.surfaceContainer, - R.attr.materialColorSurfaceContainer, + R.color.materialColorSurfaceContainer, ) addValue( "surfaceContainerHigh", colorScheme.surfaceContainerHigh, - R.attr.materialColorSurfaceContainerHigh, + R.color.materialColorSurfaceContainerHigh, ) addValue( "surfaceContainerHighest", colorScheme.surfaceContainerHighest, - R.attr.materialColorSurfaceContainerHighest, + R.color.materialColorSurfaceContainerHighest, ) addValue( "surfaceContainerLow", colorScheme.surfaceContainerLow, - R.attr.materialColorSurfaceContainerLow, + R.color.materialColorSurfaceContainerLow, ) addValue( "surfaceContainerLowest", colorScheme.surfaceContainerLowest, - R.attr.materialColorSurfaceContainerLowest, + R.color.materialColorSurfaceContainerLowest, ) } @@ -200,9 +200,9 @@ class PlatformThemeTest { "MaterialTheme.colorScheme.${colorValue.name} matches attribute color" ) .that(colorValue.materialValue) - .isEqualTo(colorValue.attrValue) + .isEqualTo(colorValue.colorValue) } } - private data class ColorValue(val name: String, val materialValue: Color, val attrValue: Color) + private data class ColorValue(val name: String, val materialValue: Color, val colorValue: Color) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Color.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Color.kt index 64b9f2df144b..81ae6b39e06b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Color.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/Color.kt @@ -19,6 +19,7 @@ package com.android.systemui.common.ui.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource import com.android.compose.theme.colorAttr /** Resolves [com.android.systemui.common.shared.model.Color] into [Color] */ @@ -28,5 +29,6 @@ fun com.android.systemui.common.shared.model.Color.toColor(): Color { return when (this) { is com.android.systemui.common.shared.model.Color.Attribute -> colorAttr(attribute) is com.android.systemui.common.shared.model.Color.Loaded -> Color(color) + is com.android.systemui.common.shared.model.Color.Resource -> colorResource(colorRes) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 4705d8dd86c4..beaf9631ae5a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -44,7 +44,6 @@ import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.observableTransitionState import com.android.compose.animation.scene.transitions -import com.android.systemui.Flags.communalHubOnMobile import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalTransitionKeys @@ -188,7 +187,7 @@ fun CommunalContainer( scene( CommunalScenes.Blank, userActions = - if (communalHubOnMobile()) emptyMap() + if (viewModel.v2FlagEnabled()) emptyMap() else mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal), ) { // This scene shows nothing only allowing for transitions to the communal scene. @@ -198,7 +197,8 @@ fun CommunalContainer( scene( CommunalScenes.Communal, userActions = - if (communalHubOnMobile()) emptyMap() else mapOf(Swipe.End to CommunalScenes.Blank), + if (viewModel.v2FlagEnabled()) emptyMap() + else mapOf(Swipe.End to CommunalScenes.Blank), ) { CommunalScene( backgroundType = backgroundType, 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 778d7e7f99b3..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,11 +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 @@ -48,6 +54,7 @@ constructor( private val ambientStatusBarSection: AmbientStatusBarSection, private val communalPopupSection: CommunalPopupSection, private val widgetSection: CommunalAppWidgetSection, + private val communalToDreamButtonSection: CommunalToDreamButtonSection, ) { @Composable @@ -59,7 +66,7 @@ constructor( Box(modifier = Modifier.fillMaxSize()) { with(communalPopupSection) { Popup() } with(ambientStatusBarSection) { - AmbientStatusBar(modifier = Modifier.fillMaxWidth()) + AmbientStatusBar(modifier = Modifier.fillMaxWidth().zIndex(1f)) } CommunalHub( viewModel = viewModel, @@ -81,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) @@ -100,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) @@ -108,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/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt index 4f1acdc4da60..6591a75f2407 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -95,7 +96,9 @@ private fun PeopleScreenWithConversations( recentTiles: List<PeopleTileViewModel>, onTileClicked: (PeopleTileViewModel) -> Unit, ) { - Column(Modifier.sysuiResTag("top_level_with_conversations")) { + Column( + Modifier.fillMaxSize().safeContentPadding().sysuiResTag("top_level_with_conversations") + ) { Column( Modifier.fillMaxWidth().padding(PeopleSpacePadding), horizontalAlignment = Alignment.CenterHorizontally, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt index d483f88edfff..9f582bc4daa9 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreenEmpty.kt @@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -47,7 +48,7 @@ import com.android.systemui.res.R @Composable internal fun PeopleScreenEmpty(onGotItClicked: () -> Unit) { Column( - Modifier.fillMaxSize().padding(PeopleSpacePadding), + Modifier.fillMaxSize().safeContentPadding().padding(PeopleSpacePadding), horizontalAlignment = Alignment.CenterHorizontally, ) { Text( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt index 2d32fd768eaa..f7ce2153b0ec 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt @@ -261,7 +261,7 @@ private fun RowScope.ForegroundServicesButton( /** A button with an icon. */ @Composable -private fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier = Modifier) { +fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier = Modifier) { Expandable( color = colorAttr(model.backgroundColor), shape = CircleShape, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt index 3fce89054b20..b1a19456ab7d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt @@ -26,8 +26,10 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeightIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -50,6 +52,8 @@ import com.android.systemui.qs.flags.QsDetailedView import com.android.systemui.qs.panels.ui.compose.EditMode import com.android.systemui.qs.panels.ui.compose.TileDetails import com.android.systemui.qs.panels.ui.compose.TileGrid +import com.android.systemui.qs.panels.ui.compose.toolbar.Toolbar +import com.android.systemui.qs.ui.composable.QuickSettingsShade.Dimensions.GridMaxHeight import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsViewModel import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel @@ -122,7 +126,9 @@ constructor( // A sealed interface to represent the possible states of the `ShadeBody` sealed interface ShadeBodyState { data object Editing : ShadeBodyState + data object TileDetails : ShadeBodyState + data object Default : ShadeBodyState } @@ -149,9 +155,8 @@ fun SceneScope.ShadeBody(viewModel: QuickSettingsContainerViewModel) { ShadeBodyState.Editing -> { EditMode( viewModel = viewModel.editModeViewModel, - modifier = Modifier - .fillMaxWidth() - .padding(QuickSettingsShade.Dimensions.Padding), + modifier = + Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding), ) } ShadeBodyState.TileDetails -> { @@ -182,22 +187,23 @@ fun SceneScope.QuickSettingsLayout( .padding( start = QuickSettingsShade.Dimensions.Padding, end = QuickSettingsShade.Dimensions.Padding, - top = QuickSettingsShade.Dimensions.Padding, + bottom = QuickSettingsShade.Dimensions.Padding / 2, ), ) { + Toolbar(viewModel.toolbarViewModelFactory) BrightnessSliderContainer( viewModel = viewModel.brightnessSliderViewModel, modifier = Modifier.fillMaxWidth().height(QuickSettingsShade.Dimensions.BrightnessSliderHeight), ) - Box { + Box( + modifier = + Modifier.requiredHeightIn(max = GridMaxHeight) + .verticalNestedScrollToScene() + .verticalScroll(rememberScrollState()) + ) { GridAnchor() - TileGrid( - viewModel = viewModel.tileGridViewModel, - modifier = - Modifier.fillMaxWidth() - .heightIn(max = QuickSettingsShade.Dimensions.GridMaxHeight), - ) + TileGrid(viewModel = viewModel.tileGridViewModel, modifier = Modifier.fillMaxWidth()) } } } @@ -207,6 +213,6 @@ object QuickSettingsShade { object Dimensions { val Padding = 16.dp val BrightnessSliderHeight = 64.dp - val GridMaxHeight = 800.dp + val GridMaxHeight = 420.dp } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index caf5e41576f3..2d589f37f3cb 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -27,8 +27,11 @@ import com.android.compose.animation.scene.content.state.TransitionState.HasOver import com.android.compose.nestedscroll.OnStopScope import com.android.compose.nestedscroll.PriorityNestedScrollConnection import com.android.compose.nestedscroll.ScrollController +import com.android.compose.ui.util.SpaceVectorConverter import kotlin.math.absoluteValue +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext internal interface DraggableHandler { /** @@ -191,9 +194,15 @@ private class DragControllerImpl( private val draggableHandler: DraggableHandlerImpl, val swipes: Swipes, var swipeAnimation: SwipeAnimation<*>, -) : DragController { +) : DragController, SpaceVectorConverter by SpaceVectorConverter(draggableHandler.orientation) { val layoutState = draggableHandler.layoutImpl.state + val overscrollableContent: OverscrollableContent = + when (draggableHandler.orientation) { + Orientation.Vertical -> draggableHandler.layoutImpl.verticalOverscrollableContent + Orientation.Horizontal -> draggableHandler.layoutImpl.horizontalOverscrollableContent + } + /** * Whether this handle is active. If this returns false, calling [onDrag] and [onStop] will do * nothing. @@ -224,36 +233,75 @@ private class DragControllerImpl( * @return the consumed delta */ override fun onDrag(delta: Float): Float { - return onDrag(delta, swipeAnimation) + val initialAnimation = swipeAnimation + if (delta == 0f || !isDrivingTransition || initialAnimation.isAnimatingOffset()) { + return 0f + } + // swipeAnimation can change during the gesture, we want to always use the initial reference + // during the whole drag gesture. + return dragWithOverscroll(delta, animation = initialAnimation) } - private fun <T : ContentKey> onDrag(delta: Float, swipeAnimation: SwipeAnimation<T>): Float { - if (delta == 0f || !isDrivingTransition || swipeAnimation.isAnimatingOffset()) { - return 0f + private fun <T : ContentKey> dragWithOverscroll( + delta: Float, + animation: SwipeAnimation<T>, + ): Float { + require(delta != 0f) { "delta should not be 0" } + var overscrollEffect = overscrollableContent.currentOverscrollEffect + + // If we're already overscrolling, continue with the current effect for a smooth finish. + if (overscrollEffect == null || !overscrollEffect.isInProgress) { + // Otherwise, determine the target content (toContent or fromContent) for the new + // overscroll effect based on the gesture's direction. + val content = animation.contentByDirection(delta) + overscrollEffect = overscrollableContent.applyOverscrollEffectOn(content) + } + + // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags. + if (!overscrollEffect.node.node.isAttached) { + return drag(delta, animation) } - val distance = swipeAnimation.distance() - val previousOffset = swipeAnimation.dragOffset + return overscrollEffect + .applyToScroll( + delta = delta.toOffset(), + source = NestedScrollSource.UserInput, + performScroll = { + val preScrollAvailable = it.toFloat() + drag(preScrollAvailable, animation).toOffset() + }, + ) + .toFloat() + } + + private fun <T : ContentKey> drag(delta: Float, animation: SwipeAnimation<T>): Float { + if (delta == 0f) return 0f + + val distance = animation.distance() + val previousOffset = animation.dragOffset val desiredOffset = previousOffset + delta - val desiredProgress = swipeAnimation.computeProgress(desiredOffset) + val desiredProgress = animation.computeProgress(desiredOffset) - // Note: the distance could be negative if fromContent is above or to the left of - // toContent. + // Note: the distance could be negative if fromContent is above or to the left of toContent. val newOffset = when { distance == DistanceUnspecified || - swipeAnimation.contentTransition.isWithinProgressRange(desiredProgress) -> + animation.contentTransition.isWithinProgressRange(desiredProgress) -> desiredOffset distance > 0f -> desiredOffset.fastCoerceIn(0f, distance) else -> desiredOffset.fastCoerceIn(distance, 0f) } - swipeAnimation.dragOffset = newOffset + animation.dragOffset = newOffset return newOffset - previousOffset } override suspend fun onStop(velocity: Float, canChangeContent: Boolean): Float { - return onStop(velocity, canChangeContent, swipeAnimation) + // To ensure that any ongoing animation completes gracefully and avoids an undefined state, + // we execute the actual `onStop` logic in a non-cancellable context. This prevents the + // coroutine from being cancelled prematurely, which could interrupt the animation. + // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags. + return withContext(NonCancellable) { onStop(velocity, canChangeContent, swipeAnimation) } } private suspend fun <T : ContentKey> onStop( @@ -304,7 +352,22 @@ private class DragControllerImpl( fromContent } - return swipeAnimation.animateOffset(velocity, targetContent) + val overscrollEffect = overscrollableContent.applyOverscrollEffectOn(targetContent) + + // TODO(b/378470603) Remove this check once NestedDraggable is used to handle drags. + if (!overscrollEffect.node.node.isAttached) { + return swipeAnimation.animateOffset(velocity, targetContent) + } + + overscrollEffect.applyToFling( + velocity = velocity.toVelocity(), + performFling = { + val velocityLeft = it.toFloat() + swipeAnimation.animateOffset(velocityLeft, targetContent).toVelocity() + }, + ) + + return velocity } /** diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index a14b2b3746f5..bf7e8e823658 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection +import com.android.compose.animation.scene.effect.ContentOverscrollEffect /** * [SceneTransitionLayout] is a container that automatically animates its content whenever its state @@ -283,6 +284,53 @@ typealias SceneScope = ContentScope @ElementDsl interface ContentScope : BaseContentScope { /** + * The overscroll effect applied to the content in the vertical direction. This can be used to + * customize how the content behaves when the scene is over scrolled. + * + * For example, you can use it with the `Modifier.overscroll()` modifier: + * ```kotlin + * @Composable + * fun ContentScope.MyScene() { + * Box( + * modifier = Modifier + * // Apply the effect + * .overscroll(verticalOverscrollEffect) + * ) { + * // ... your content ... + * } + * } + * ``` + * + * Or you can read the `overscrollDistance` value directly, if you need some custom overscroll + * behavior: + * ```kotlin + * @Composable + * fun ContentScope.MyScene() { + * Box( + * modifier = Modifier + * .graphicsLayer { + * // Translate half of the overscroll + * translationY = verticalOverscrollEffect.overscrollDistance * 0.5f + * } + * ) { + * // ... your content ... + * } + * } + * ``` + * + * @see horizontalOverscrollEffect + */ + val verticalOverscrollEffect: ContentOverscrollEffect + + /** + * The overscroll effect applied to the content in the horizontal direction. This can be used to + * customize how the content behaves when the scene is over scrolled. + * + * @see verticalOverscrollEffect + */ + val horizontalOverscrollEffect: ContentOverscrollEffect + + /** * Animate some value at the content level. * * @param value the value of this shared value in the current content. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index bdc1461f06c9..d7bac147d8f2 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -49,8 +49,10 @@ import com.android.compose.animation.scene.content.Content import com.android.compose.animation.scene.content.Overlay import com.android.compose.animation.scene.content.Scene import com.android.compose.animation.scene.content.state.TransitionState +import com.android.compose.animation.scene.effect.GestureEffect import com.android.compose.ui.util.lerp import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch /** The type for the content of movable elements. */ internal typealias MovableElementContent = @Composable (@Composable () -> Unit) -> Unit @@ -134,6 +136,18 @@ internal class SceneTransitionLayoutImpl( _movableContents = it } + internal var horizontalOverscrollableContent = + OverscrollableContent( + animationScope = animationScope, + overscrollEffect = { content(it).scope.horizontalOverscrollGestureEffect }, + ) + + internal var verticalOverscrollableContent = + OverscrollableContent( + animationScope = animationScope, + overscrollEffect = { content(it).scope.verticalOverscrollGestureEffect }, + ) + /** * The different values of a shared value keyed by a a [ValueKey] and the different elements and * contents it is associated to. @@ -561,3 +575,23 @@ private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) : return layout(width, height) { placeable.place(0, 0) } } } + +internal class OverscrollableContent( + private val animationScope: CoroutineScope, + private val overscrollEffect: (ContentKey) -> GestureEffect, +) { + private var currentContent: ContentKey? = null + var currentOverscrollEffect: GestureEffect? = null + + fun applyOverscrollEffectOn(contentKey: ContentKey): GestureEffect { + if (currentContent == contentKey) return currentOverscrollEffect!! + + currentOverscrollEffect?.apply { animationScope.launch { ensureApplyToFlingIsCalled() } } + + // We are wrapping the overscroll effect. + val overscrollEffect = overscrollEffect(contentKey) + currentContent = contentKey + currentOverscrollEffect = overscrollEffect + return overscrollEffect + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt index ae235e5097af..59d0b55c1db8 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt @@ -313,6 +313,17 @@ internal class SwipeAnimation<T : ContentKey>( fun isAnimatingOffset(): Boolean = offsetAnimation != null + /** Get the [ContentKey] ([fromContent] or [toContent]) associated to the current [direction] */ + fun contentByDirection(direction: Float): T { + require(direction != 0f) { "Cannot find a content in this direction: $direction" } + val isDirectionToContent = (isUpOrLeft && direction < 0) || (!isUpOrLeft && direction > 0) + return if (isDirectionToContent) { + toContent + } else { + fromContent + } + } + /** * Animate the offset to a [targetContent], using the [initialVelocity] and an optional [spec] * @@ -326,13 +337,6 @@ internal class SwipeAnimation<T : ContentKey>( check(!isAnimatingOffset()) { "SwipeAnimation.animateOffset() can only be called once" } val initialProgress = progress - // Skip the animation if we have already reached the target content and the overscroll does - // not animate anything. - val hasReachedTargetContent = - (targetContent == toContent && initialProgress >= 1f) || - (targetContent == fromContent && initialProgress <= 0f) - val skipAnimation = - hasReachedTargetContent && !contentTransition.isWithinProgressRange(initialProgress) val targetContent = if (targetContent != currentContent && !canChangeContent(targetContent)) { @@ -341,6 +345,14 @@ internal class SwipeAnimation<T : ContentKey>( targetContent } + // Skip the animation if we have already reached the target content and the overscroll does + // not animate anything. + val hasReachedTargetContent = + (targetContent == toContent && initialProgress >= 1f) || + (targetContent == fromContent && initialProgress <= 0f) + val skipAnimation = + hasReachedTargetContent && !contentTransition.isWithinProgressRange(initialProgress) + val targetOffset = if (targetContent == fromContent) { 0f diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 8c4cd8c93b87..152f05eb5cc7 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -17,6 +17,7 @@ package com.android.compose.animation.scene.content import android.annotation.SuppressLint +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable @@ -51,6 +52,9 @@ import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateSharedValueAsState +import com.android.compose.animation.scene.effect.GestureEffect +import com.android.compose.animation.scene.effect.OffsetOverscrollEffect +import com.android.compose.animation.scene.effect.VisualEffect import com.android.compose.animation.scene.element import com.android.compose.animation.scene.modifiers.noResizeDuringTransitions import com.android.compose.animation.scene.nestedScrollToScene @@ -109,6 +113,26 @@ internal class ContentScopeImpl( override val layoutState: SceneTransitionLayoutState = layoutImpl.state + private val _verticalOverscrollEffect = + OffsetOverscrollEffect( + orientation = Orientation.Vertical, + animationScope = layoutImpl.animationScope, + ) + + private val _horizontalOverscrollEffect = + OffsetOverscrollEffect( + orientation = Orientation.Horizontal, + animationScope = layoutImpl.animationScope, + ) + + val verticalOverscrollGestureEffect = GestureEffect(_verticalOverscrollEffect) + + val horizontalOverscrollGestureEffect = GestureEffect(_horizontalOverscrollEffect) + + override val verticalOverscrollEffect = VisualEffect(_verticalOverscrollEffect) + + override val horizontalOverscrollEffect = VisualEffect(_horizontalOverscrollEffect) + override fun Modifier.element(key: ElementKey): Modifier { return element(layoutImpl, content, key) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt new file mode 100644 index 000000000000..2233debde277 --- /dev/null +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.effect + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.unit.Velocity +import com.android.compose.ui.util.SpaceVectorConverter +import kotlin.math.abs +import kotlin.math.sign +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +/** + * An [OverscrollEffect] that uses an [Animatable] to track and animate overscroll values along a + * specific [Orientation]. + */ +interface ContentOverscrollEffect : OverscrollEffect { + /** The current overscroll value. */ + val overscrollDistance: Float +} + +open class BaseContentOverscrollEffect( + orientation: Orientation, + private val animationScope: CoroutineScope, + private val animationSpec: AnimationSpec<Float>, +) : ContentOverscrollEffect, SpaceVectorConverter by SpaceVectorConverter(orientation) { + + /** The [Animatable] that holds the current overscroll value. */ + private val animatable = Animatable(initialValue = 0f, visibilityThreshold = 0.5f) + + override val overscrollDistance: Float + get() = animatable.value + + override val isInProgress: Boolean + get() = overscrollDistance != 0f + + override fun applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset { + val deltaForAxis = delta.toFloat() + + // If we're currently overscrolled, and the user scrolls in the opposite direction, we need + // to "relax" the overscroll by consuming some of the scroll delta to bring it back towards + // zero. + val currentOffset = animatable.value + val sameDirection = deltaForAxis.sign == currentOffset.sign + val consumedByPreScroll = + if (abs(currentOffset) > 0.5 && !sameDirection) { + // The user has scrolled in the opposite direction. + val prevOverscrollValue = currentOffset + val newOverscrollValue = currentOffset + deltaForAxis + if (sign(prevOverscrollValue) != sign(newOverscrollValue)) { + // Enough to completely cancel the overscroll. We snap the overscroll value + // back to zero and consume the corresponding amount of the scroll delta. + animationScope.launch { animatable.snapTo(0f) } + -prevOverscrollValue + } else { + // Not enough to cancel the overscroll. We update the overscroll value + // accordingly and consume the entire scroll delta. + animationScope.launch { animatable.snapTo(newOverscrollValue) } + deltaForAxis + } + } else { + 0f + } + .toOffset() + + // After handling any overscroll relaxation, we pass the remaining scroll delta to the + // standard scrolling logic. + val leftForScroll = delta - consumedByPreScroll + val consumedByScroll = performScroll(leftForScroll) + val overscrollDelta = leftForScroll - consumedByScroll + + // If the user is dragging (not flinging), and there's any remaining scroll delta after the + // standard scrolling logic has been applied, we add it to the overscroll. + if (abs(overscrollDelta.toFloat()) > 0.5 && source == NestedScrollSource.UserInput) { + animationScope.launch { animatable.snapTo(currentOffset + overscrollDelta.toFloat()) } + } + + return delta + } + + override suspend fun applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { + // We launch a coroutine to ensure the fling animation starts after any pending [snapTo] + // animations have finished. + // This guarantees a smooth, sequential execution of animations on the overscroll value. + coroutineScope { + launch { + val consumed = performFling(velocity) + val remaining = velocity - consumed + animatable.animateTo(0f, animationSpec, remaining.toFloat()) + } + } + } +} + +/** An overscroll effect that ensures only a single fling animation is triggered. */ +internal class GestureEffect(private val delegate: ContentOverscrollEffect) : + ContentOverscrollEffect by delegate { + private var shouldFling = false + + override fun applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset { + shouldFling = true + return delegate.applyToScroll(delta, source, performScroll) + } + + override suspend fun applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { + if (!shouldFling) { + performFling(velocity) + return + } + shouldFling = false + delegate.applyToFling(velocity, performFling) + } + + suspend fun ensureApplyToFlingIsCalled() { + applyToFling(Velocity.Zero) { Velocity.Zero } + } +} + +/** + * An overscroll effect that only applies visual effects and does not interfere with the actual + * scrolling or flinging behavior. + */ +internal class VisualEffect(private val delegate: ContentOverscrollEffect) : + ContentOverscrollEffect by delegate { + override fun applyToScroll( + delta: Offset, + source: NestedScrollSource, + performScroll: (Offset) -> Offset, + ): Offset { + return performScroll(delta) + } + + override suspend fun applyToFling( + velocity: Velocity, + performFling: suspend (Velocity) -> Velocity, + ) { + performFling(velocity) + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt new file mode 100644 index 000000000000..f459c46d3e6f --- /dev/null +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.effect + +import androidx.annotation.VisibleForTesting +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.foundation.OverscrollEffect +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.DelegatableNode +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ProgressConverter +import kotlin.math.roundToInt +import kotlinx.coroutines.CoroutineScope + +/** An [OverscrollEffect] that offsets the content by the overscroll value. */ +class OffsetOverscrollEffect( + orientation: Orientation, + animationScope: CoroutineScope, + animationSpec: AnimationSpec<Float> = DefaultAnimationSpec, +) : BaseContentOverscrollEffect(orientation, animationScope, animationSpec) { + private var _node: DelegatableNode = newNode() + override val node: DelegatableNode + get() = _node + + fun newNode(): DelegatableNode { + return object : Modifier.Node(), LayoutModifierNode { + override fun onDetach() { + super.onDetach() + // TODO(b/379086317) Remove this workaround: avoid to reuse the same node. + _node = newNode() + } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints, + ): MeasureResult { + val placeable = measurable.measure(constraints) + return layout(placeable.width, placeable.height) { + val offsetPx = computeOffset(density = this@measure, overscrollDistance) + placeable.placeRelativeWithLayer(position = offsetPx.toIntOffset()) + } + } + } + } + + companion object { + private val MaxDistance = 400.dp + + internal val DefaultAnimationSpec = + spring( + stiffness = Spring.StiffnessLow, + dampingRatio = Spring.DampingRatioLowBouncy, + visibilityThreshold = 0.5f, + ) + + @VisibleForTesting + internal fun computeOffset(density: Density, overscrollDistance: Float): Int { + val maxDistancePx = with(density) { MaxDistance.toPx() } + val progress = ProgressConverter.Default.convert(overscrollDistance / maxDistancePx) + return (progress * maxDistancePx).roundToInt() + } + } +} + +@Composable +fun rememberOffsetOverscrollEffect( + orientation: Orientation, + animationSpec: AnimationSpec<Float> = OffsetOverscrollEffect.DefaultAnimationSpec, +): OffsetOverscrollEffect { + val animationScope = rememberCoroutineScope() + return remember(orientation, animationScope, animationSpec) { + OffsetOverscrollEffect(orientation, animationScope, animationSpec) + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt index a5be4dc195bc..98a00173f1d7 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt @@ -48,8 +48,8 @@ fun LargeTopAppBarNestedScrollConnection( orientation = Orientation.Vertical, // When swiping up, the LargeTopAppBar will shrink (to [minHeight]) and the content will // expand. Then, you can then scroll down the content. - canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ -> - offsetAvailable < 0 && offsetBeforeStart == 0f && height() > minHeight() + canStartPreScroll = { offsetAvailable, _, _ -> + offsetAvailable < 0 && height() > minHeight() }, // When swiping down, the content will scroll up until it reaches the top. Then, the // LargeTopAppBar will expand until it reaches its [maxHeight]. diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 2c8dc3264b7e..b20056d54de1 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -42,7 +42,6 @@ import com.android.compose.animation.scene.content.state.TransitionState.Transit import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.MonotonicClockTestScope import com.android.compose.test.runMonotonicClockTest -import com.android.compose.test.transition import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred @@ -921,6 +920,28 @@ class DraggableHandlerTest { } @Test + fun blockTransition_animated() = runGestureTest { + assertIdle(SceneA) + layoutState.transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) } + + // Swipe up to scene B. Overscroll 50%. + val dragController = onDragStarted(overSlop = up(1.5f), expectedConsumedOverSlop = up(1.0f)) + assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB, progress = 1f) + + // Block the transition when the user release their finger. + canChangeScene = { false } + val velocityConsumed = + dragController.onDragStoppedAnimateLater(velocity = -velocityThreshold) + + // Start an animation: overscroll and from 1f to 0f. + assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB, progress = 1f) + + val consumed = velocityConsumed.await() + assertThat(consumed).isEqualTo(-velocityThreshold) + assertIdle(SceneA) + } + + @Test fun scrollFromIdleWithNoTargetScene_shouldUseOverscrollSpecIfAvailable() = runGestureTest { layoutState.transitions = transitions { overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) } 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 a301856d024f..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 @@ -30,6 +30,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size +import androidx.compose.foundation.overscroll import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.material3.Text @@ -47,6 +48,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.layout.approachLayout import androidx.compose.ui.layout.layout +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.assertIsDisplayed @@ -60,6 +62,7 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performTouchInput +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpSize @@ -72,6 +75,7 @@ import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState +import com.android.compose.animation.scene.effect.OffsetOverscrollEffect import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.assertSizeIsEqualTo import com.android.compose.test.setContentAndCreateMainScope @@ -712,7 +716,7 @@ class ElementTest { } @Test - fun elementTransitionDuringOverscroll() { + fun elementTransitionDuringOverscrollWithOverscrollDSL() { val layoutWidth = 200.dp val layoutHeight = 400.dp val overscrollTranslateY = 10.dp @@ -765,6 +769,241 @@ class ElementTest { assertThat(animatedFloat).isEqualTo(100f) } + private fun expectedOffset(currentOffset: Dp, density: Density): Dp { + return with(density) { + OffsetOverscrollEffect.computeOffset(density, currentOffset.toPx()).toDp() + } + } + + @Test + fun elementTransitionDuringOverscroll() { + val layoutWidth = 200.dp + val layoutHeight = 400.dp + lateinit var density: Density + + // 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 state = + rule.runOnUiThread { + MutableSceneTransitionLayoutState( + initialScene = SceneA, + transitions = transitions { overscrollDisabled(SceneB, Orientation.Vertical) }, + ) + } + rule.setContent { + density = LocalDensity.current + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer(Modifier.fillMaxSize()) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Foo) + ) + } + } + } + assertThat(state.transitionState).isIdle() + + // Swipe by half of verticalSwipeDistance. + rule.onRoot().performTouchInput { + val middleTop = Offset((layoutWidth / 2).toPx(), 0f) + down(middleTop) + // Scroll 50%. + val firstScrollHeight = layoutHeight.toPx() * 0.5f + moveBy(Offset(0f, touchSlop + firstScrollHeight), delayMillis = 1_000) + } + + rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp) + val transition = assertThat(state.transitionState).isSceneTransition() + assertThat(transition).isNotNull() + assertThat(transition).hasProgress(0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100%. + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 150% (Scene B overscroll by 50%). + assertThat(transition).hasProgress(1f) + + rule + .onNodeWithTag(TestElements.Foo.testTag) + .assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * 0.5f, density)) + } + + @Test + fun elementTransitionOverscrollMultipleScenes() { + val layoutWidth = 200.dp + val layoutHeight = 400.dp + lateinit var density: Density + + // 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 state = + rule.runOnUiThread { + MutableSceneTransitionLayoutState( + initialScene = SceneA, + transitions = + transitions { + overscrollDisabled(SceneA, Orientation.Vertical) + overscrollDisabled(SceneB, Orientation.Vertical) + }, + ) + } + rule.setContent { + density = LocalDensity.current + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Foo) + ) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .fillMaxSize() + .element(TestElements.Bar) + ) + } + } + } + assertThat(state.transitionState).isIdle() + + // Swipe by half of verticalSwipeDistance. + rule.onRoot().performTouchInput { + val middleTop = Offset((layoutWidth / 2).toPx(), 0f) + down(middleTop) + val firstScrollHeight = layoutHeight.toPx() * 0.5f // Scroll 50% + moveBy(Offset(0f, touchSlop + firstScrollHeight), delayMillis = 1_000) + } + + rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(TestElements.Bar.testTag).assertTopPositionInRootIsEqualTo(0.dp) + val transition = assertThat(state.transitionState).isSceneTransition() + assertThat(transition).isNotNull() + assertThat(transition).hasProgress(0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100%. + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 150% (Scene B overscroll by 50%). + assertThat(transition).hasProgress(1f) + + rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp) + rule + .onNodeWithTag(TestElements.Bar.testTag) + .assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * 0.5f, density)) + + rule.onRoot().performTouchInput { + // Scroll another -30%. + moveBy(Offset(0f, layoutHeight.toPx() * -0.3f), delayMillis = 1_000) + } + + // Scroll 120% (Scene B overscroll by 20%). + assertThat(transition).hasProgress(1f) + + rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp) + rule + .onNodeWithTag(TestElements.Bar.testTag) + .assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * 0.2f, density)) + rule.onRoot().performTouchInput { + // Scroll another -70% + moveBy(Offset(0f, layoutHeight.toPx() * -0.7f), delayMillis = 1_000) + } + + // Scroll 50% (No overscroll). + assertThat(transition).hasProgress(0.5f) + + rule.onNodeWithTag(TestElements.Foo.testTag).assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(TestElements.Bar.testTag).assertTopPositionInRootIsEqualTo(0.dp) + + rule.onRoot().performTouchInput { + // Scroll another -100%. + moveBy(Offset(0f, layoutHeight.toPx() * -1f), delayMillis = 1_000) + } + + // Scroll -50% (Scene A overscroll by -50%). + assertThat(transition).hasProgress(0f) + rule + .onNodeWithTag(TestElements.Foo.testTag) + .assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * -0.5f, density)) + rule.onNodeWithTag(TestElements.Bar.testTag).assertTopPositionInRootIsEqualTo(0.dp) + } + + @Test + fun elementTransitionOverscroll() { + val layoutWidth = 200.dp + val layoutHeight = 400.dp + lateinit var density: Density + + // 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 state = + rule.runOnUiThread { + MutableSceneTransitionLayoutState( + initialScene = SceneA, + transitions = + transitions { + defaultOverscrollProgressConverter = ProgressConverter.linear() + overscrollDisabled(SceneB, Orientation.Vertical) + }, + ) + } + rule.setContent { + density = LocalDensity.current + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { + scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { + Spacer(Modifier.fillMaxSize()) + } + scene(SceneB) { + Spacer( + Modifier.overscroll(verticalOverscrollEffect) + .element(TestElements.Foo) + .fillMaxSize() + ) + } + } + } + assertThat(state.transitionState).isIdle() + + // Swipe by half of verticalSwipeDistance. + rule.onRoot().performTouchInput { + val middleTop = Offset((layoutWidth / 2).toPx(), 0f) + down(middleTop) + val firstScrollHeight = layoutHeight.toPx() * 0.5f // Scroll 50% + moveBy(Offset(0f, touchSlop + firstScrollHeight), delayMillis = 1_000) + } + + val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag) + fooElement.assertTopPositionInRootIsEqualTo(0.dp) + val transition = assertThat(state.transitionState).isSceneTransition() + assertThat(transition).isNotNull() + assertThat(transition).hasProgress(0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100%. + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 150% (Scene B overscroll by 50%). + assertThat(transition).hasProgress(1f) + + fooElement.assertTopPositionInRootIsEqualTo(expectedOffset(layoutHeight * 0.5f, density)) + } + @Test fun elementTransitionDuringNestedScrollOverscroll() { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is 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 new file mode 100644 index 000000000000..da8fe3094448 --- /dev/null +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.effect + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.rememberScrollableState +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.overscroll +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performTouchInput +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 + +@RunWith(AndroidJUnit4::class) +class OffsetOverscrollEffectTest { + @get:Rule val rule = createComposeRule() + + 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() + } + } + } + + 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. + lateinit var density: Density + rule.setContent { + density = LocalDensity.current + touchSlop = LocalViewConfiguration.current.touchSlop + val overscrollEffect = rememberOffsetOverscrollEffect(overscrollEffectOrientation) + + Box( + Modifier.overscroll(overscrollEffect) + // A scrollable that does not consume the scroll gesture. + .scrollable( + state = rememberScrollableState { 0f }, + orientation = scrollableOrientation, + overscrollEffect = overscrollEffect, + ) + .size(layoutSize) + .testTag(BOX_TAG) + ) + } + return LayoutInfo(layoutSize, touchSlop, density) + } + + @Test + fun applyVerticalOffset_duringVerticalOverscroll() { + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) + + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + + rule.onRoot().performTouchInput { + down(center) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) + } + + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) + } + + @Test + fun applyNoOffset_duringHorizontalOverscroll() { + val info = + setupOverscrollableBox( + scrollableOrientation = Orientation.Vertical, + overscrollEffectOrientation = Orientation.Horizontal, + ) + + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + + rule.onRoot().performTouchInput { + down(center) + moveBy(Offset(info.touchSlop + info.layoutSize.toPx(), 0f), delayMillis = 1_000) + } + + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + } + + @Test + fun backToZero_afterOverscroll() { + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) + + rule.onRoot().performTouchInput { + down(center) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) + } + + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) + + rule.onRoot().performTouchInput { up() } + + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + } + + @Test + fun offsetOverscroll_followTheTouchPointer() { + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) + + // First gesture, drag down. + rule.onRoot().performTouchInput { + down(center) + // A full screen scroll. + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) + } + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) + + rule.onRoot().performTouchInput { + // Reduced by half. + 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) + } + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(-info.layoutSize)) + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt index e27f9b52153d..c8fb2cb8474f 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt @@ -71,41 +71,6 @@ class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) { } @Test - fun onScrollUpAfterContentScrolled_ignoreUpEvent() { - val scrollConnection = buildScrollConnection(heightRange = 0f..2f) - height = 1f - - // scroll down consumed by a child - scrollConnection.scroll(available = Offset(0f, 1f), consumedByScroll = Offset(0f, 1f)) - - val offsetConsumed = - scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource) - - // It should ignore all onPreScroll events - assertThat(offsetConsumed).isEqualTo(Offset.Zero) - assertThat(height).isEqualTo(1f) - } - - @Test - fun onScrollUpAfterContentReturnedToZero_consumeHeight() { - val scrollConnection = buildScrollConnection(heightRange = 0f..2f) - height = 1f - - // scroll down consumed by a child - scrollConnection.scroll(available = Offset(0f, 1f), consumedByScroll = Offset(0f, 1f)) - - // scroll up consumed by a child, the child is in its original position - scrollConnection.scroll(available = Offset(0f, -1f), consumedByScroll = Offset(0f, -1f)) - - val offsetConsumed = - scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource) - - // It should ignore all onPreScroll events - assertThat(offsetConsumed).isEqualTo(Offset(0f, -1f)) - assertThat(height).isEqualTo(0f) - } - - @Test fun onScrollUp_consumeDownToMin() { val scrollConnection = buildScrollConnection(heightRange = 0f..2f) height = 0f diff --git a/packages/SystemUI/lint-baseline.xml b/packages/SystemUI/lint-baseline.xml index 00b0c44c2077..523adc6d3144 100644 --- a/packages/SystemUI/lint-baseline.xml +++ b/packages/SystemUI/lint-baseline.xml @@ -26857,8 +26857,8 @@ <issue id="Overdraw" - message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorOnSurfaceVariant` with a theme that also paints a background (inferred theme is `@style/Theme.SystemUI`)" - errorLine1=" android:background="?androidprv:attr/materialColorOnSurfaceVariant" />" + message="Possible overdraw: Root element paints background `@androidprv:color/materialColorOnSurfaceVariant` with a theme that also paints a background (inferred theme is `@style/Theme.SystemUI`)" + errorLine1=" android:background="@androidprv:color/materialColorOnSurfaceVariant" />" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SystemUI/res/layout/notification_children_divider.xml" @@ -26868,8 +26868,8 @@ <issue id="Overdraw" - message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorSurfaceContainerHigh` with a theme that also paints a background (inferred theme is `@style/Theme.SystemUI`)" - errorLine1=" android:background="?androidprv:attr/materialColorSurfaceContainerHigh"" + message="Possible overdraw: Root element paints background `@androidprv:color/materialColorSurfaceContainerHigh` with a theme that also paints a background (inferred theme is `@style/Theme.SystemUI`)" + errorLine1=" android:background="@androidprv:color/materialColorSurfaceContainerHigh"" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SystemUI/res/layout/notification_snooze.xml" @@ -33644,7 +33644,7 @@ <issue id="ShadeDisplayAwareContextChecker" - message="UI elements of the shade window
should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only
@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so
might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).
If the usage of Resources is not related to display specific configuration or UI, then there is
technically no need to use the annotation, and you can annotate the class with
@SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" errorLine1=" @Main resources: Resources," errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location @@ -33655,7 +33655,7 @@ <issue id="ShadeDisplayAwareContextChecker" - message="UI elements of the shade window
should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only
@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so
might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).
If the usage of Context is not related to display specific configuration or UI, then there is
technically no need to use the annotation, and you can annotate the class with
@SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" errorLine1="constructor(context: Context, val shadeViewController: ShadeViewController) {" errorLine2=" ~~~~~~~~~~~~~~~~"> <location @@ -33699,7 +33699,7 @@ <issue id="ShadeDisplayAwareContextChecker" - message="UI elements of the shade window
should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only
@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so
might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).
If the usage of Resources is not related to display specific configuration or UI, then there is
technically no need to use the annotation, and you can annotate the class with
@SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" errorLine1=" @Main private val resources: Resources," errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location @@ -33763,5 +33763,202 @@ column="5"/> </issue> + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" public AuthController(Context context," + errorLine2=" ~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java" + line="716" + column="35"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of WindowManager is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @NonNull WindowManager windowManager," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java" + line="721" + column="36"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" private val sysuiContext: Context," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt" + line="72" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated ConfigurationController, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of ConfigurationController is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" private val configurationController: ConfigurationController," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt" + line="74" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" Context context," + errorLine2=" ~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java" + line="46" + column="21"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main Resources resources," + errorLine2=" ~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java" + line="52" + column="29"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" public BiometricNotificationService(@NonNull Context context," + errorLine2=" ~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java" + line="148" + column="58"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" c: Context," + errorLine2=" ~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt" + line="61" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main private val resources: Resources," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt" + line="39" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main private val resources: Resources," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt" + line="37" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main private val resources: Resources," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt" + line="42" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @NonNull final Context context," + errorLine2=" ~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java" + line="186" + column="36"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1="class IconBuilder @Inject constructor(private val context: Context) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt" + line="27" + column="39"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of WindowManager is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" private val windowManager: WindowManager," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt" + line="40" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main resources: Resources," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt" + line="53" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Resources is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @Main private val resources: Resources," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt" + line="51" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" private val context: Context," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt" + line="51" + column="5"/> + </issue> + + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of WindowManager is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" windowManager: WindowManager," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt" + line="53" + column="5"/> + </issue> </issues> diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java index fa8cdcc4ce2b..80de087971c5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java @@ -24,6 +24,7 @@ import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -39,6 +40,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -54,11 +56,15 @@ public class DragToInteractAnimationControllerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Mock + private AccessibilityManager mAccessibilityManager; + @Before public void setUp() throws Exception { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); final SecureSettings mockSecureSettings = TestUtils.mockSecureSettings(); - final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mockSecureSettings); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, + mockSecureSettings); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); final MenuView stubMenuView = spy(new MenuView(mContext, stubMenuViewModel, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java index 7e4b6f913770..24f3a29e64ee 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java @@ -16,11 +16,16 @@ package com.android.systemui.accessibility.floatingmenu; +import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import android.content.Context; import android.content.res.Configuration; +import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -28,6 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.settings.SecureSettings; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -36,6 +42,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; /** Tests for {@link MenuInfoRepository}. */ @@ -46,16 +54,30 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { public MockitoRule mockito = MockitoJUnit.rule(); @Mock + private AccessibilityManager mAccessibilityManager; + + @Mock private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged; @Mock private SecureSettings mSecureSettings; private MenuInfoRepository mMenuInfoRepository; + private final List<String> mShortcutTargets = new ArrayList<>(); @Before public void setUp() { - mMenuInfoRepository = new MenuInfoRepository(mContext, mMockSettingsContentsChanged, - mSecureSettings); + mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); + mShortcutTargets.add(MAGNIFICATION_CONTROLLER_NAME); + doReturn(mShortcutTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets( + anyInt()); + + mMenuInfoRepository = new MenuInfoRepository(mContext, mAccessibilityManager, + mMockSettingsContentsChanged, mSecureSettings); + } + + @After + public void tearDown() { + mShortcutTargets.clear(); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java index 1f48bec97b2d..157cccc3d62f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java @@ -83,7 +83,8 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); - final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mSecureSettings); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, + mSecureSettings); final int halfScreenHeight = stubWindowManager.getCurrentWindowMetrics().getBounds().height() / 2; diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java index f7b81cc49f0b..46f076a75116 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java @@ -33,6 +33,7 @@ import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.recyclerview.widget.RecyclerView; @@ -52,6 +53,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -78,11 +80,15 @@ public class MenuListViewTouchHandlerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Mock + private AccessibilityManager mAccessibilityManager; + @Before public void setUp() throws Exception { final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final SecureSettings secureSettings = TestUtils.mockSecureSettings(); - final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, secureSettings); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, + secureSettings); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, windowManager); mStubMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java index c1708d175224..ee8ce17cecd4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java @@ -32,6 +32,7 @@ import android.graphics.drawable.GradientDrawable; import android.platform.test.annotations.EnableFlags; import android.testing.TestableLooper; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -48,6 +49,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -66,6 +68,9 @@ public class MenuViewTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Mock + private AccessibilityManager mAccessibilityManager; + private SysuiTestableContext mSpyContext; @Before @@ -84,7 +89,8 @@ public class MenuViewTest extends SysuiTestCase { doNothing().when(mSpyContext).startActivity(any()); final SecureSettings secureSettings = TestUtils.mockSecureSettings(); - final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, secureSettings); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, + secureSettings); final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); mStubMenuViewAppearance = new MenuViewAppearance(mSpyContext, stubWindowManager); mMenuView = spy(new MenuView(mSpyContext, stubMenuViewModel, mStubMenuViewAppearance, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index d75c0138bcbf..ab936590de93 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -1589,7 +1589,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa val logoInfo by collectLastValue(kosmos.promptViewModel.logoInfo) assertThat(logoInfo).isNotNull() assertThat(logoInfo!!.first).isEqualTo(defaultLogoIconWithBadge) - assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionWithBadge) + // Logo label does not use badge info. + assertThat(logoInfo!!.second).isEqualTo(defaultLogoDescriptionFromAppInfo) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt index 84d062a3e7be..831012c88f7b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt @@ -30,7 +30,6 @@ import android.view.windowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.airbnb.lottie.model.KeyPath -import com.android.settingslib.Utils import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository @@ -77,20 +76,14 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { private val contextDisplayInfo = DisplayInfo() - private val indicatorColor = - Utils.getColorAttrDefaultColor( - context, - com.android.internal.R.attr.materialColorPrimaryFixed, + private val indicatorColor = context.getColor( + com.android.internal.R.color.materialColorPrimaryFixed, ) - private val outerRimColor = - Utils.getColorAttrDefaultColor( - context, - com.android.internal.R.attr.materialColorPrimaryFixedDim, + private val outerRimColor = context.getColor( + com.android.internal.R.color.materialColorPrimaryFixedDim, ) - private val chevronFill = - Utils.getColorAttrDefaultColor( - context, - com.android.internal.R.attr.materialColorOnPrimaryFixed, + private val chevronFill = context.getColor( + com.android.internal.R.color.materialColorOnPrimaryFixed, ) private val color_blue400 = context.getColor(com.android.settingslib.color.R.color.settingslib_color_blue400) 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/dreams/DreamOverlayRegistrantTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt index 790df03e6401..1e937b46dbcb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayRegistrantTest.kt @@ -29,8 +29,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.log.core.FakeLogBuffer import com.android.systemui.shared.condition.Monitor +import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor import kotlin.test.Test import org.junit.Before @@ -48,6 +51,8 @@ import org.mockito.kotlin.whenever @TestableLooper.RunWithLooper @RunWith(AndroidJUnit4::class) class DreamOverlayRegistrantTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val context = mock<Context>() private val packageManager = mock<PackageManager>() @@ -73,6 +78,7 @@ class DreamOverlayRegistrantTest : SysuiTestCase() { monitor, packageManager, dreamManager, + kosmos.communalSettingsInteractor, logBuffer, ) @@ -117,7 +123,7 @@ class DreamOverlayRegistrantTest : SysuiTestCase() { /** Verify overlay registered when enabled in manifest. */ @Test - @DisableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE) + @DisableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) fun testRegisteredWhenEnabledWithManifest() { serviceInfo.enabled = true start() @@ -127,8 +133,10 @@ class DreamOverlayRegistrantTest : SysuiTestCase() { /** Verify overlay registered for mobile hub with flag. */ @Test - @EnableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE) + @EnableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) fun testRegisteredForMobileHub() { + kosmos.setCommunalV2ConfigEnabled(true) + start() verify(dreamManager).registerDreamOverlayService(componentName) @@ -139,7 +147,7 @@ class DreamOverlayRegistrantTest : SysuiTestCase() { * enabled. */ @Test - @DisableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE) + @DisableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) fun testDisabledForMobileWithoutMobileHub() { start() @@ -154,8 +162,9 @@ class DreamOverlayRegistrantTest : SysuiTestCase() { /** Ensure service unregistered when component is disabled at runtime. */ @Test - @EnableFlags(Flags.FLAG_COMMUNAL_HUB_ON_MOBILE) + @EnableFlags(Flags.FLAG_GLANCEABLE_HUB_V2) fun testUnregisteredWhenComponentDisabled() { + kosmos.setCommunalV2ConfigEnabled(true) start() verify(dreamManager).registerDreamOverlayService(componentName) clearInvocations(dreamManager) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt index f924ccb42cb0..b07097d61b96 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt @@ -43,7 +43,7 @@ import com.android.internal.logging.UiEventLogger import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Flags.FLAG_COMMUNAL_HUB -import com.android.systemui.Flags.FLAG_COMMUNAL_HUB_ON_MOBILE +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.SysuiTestCase import com.android.systemui.ambient.touch.TouchHandler @@ -55,7 +55,9 @@ import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepositor import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.shared.log.CommunalUiEvent import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.complication.ComplicationHostViewController @@ -262,6 +264,7 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() { mKeyguardUpdateMonitor, mScrimManager, mCommunalInteractor, + kosmos.communalSettingsInteractor, kosmos.sceneInteractor, mSystemDialogsCloser, mUiEventLogger, @@ -1283,7 +1286,7 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() { environmentComponents.verifyNoMoreInteractions() } - @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE) + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun testAmbientTouchHandlersRegistration_registerHideComplicationAndCommunal() { val client = client @@ -1303,9 +1306,11 @@ class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() { .containsExactly(mHideComplicationTouchHandler, mCommunalTouchHandler) } - @EnableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun testAmbientTouchHandlersRegistration_v2_registerOnlyHideComplication() { + kosmos.setCommunalV2ConfigEnabled(true) + val client = client // Inform the overlay service of dream starting. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt index 76434ee54627..1de38ee3a04e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/ui/viewmodel/KeyboardTouchpadTutorialViewModelTest.kt @@ -16,10 +16,8 @@ package com.android.systemui.inputdevice.tutorial.ui.viewmodel -import androidx.lifecycle.Lifecycle.Event -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.LifecycleRegistry import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.testing.TestLifecycleOwner import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -55,7 +53,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.mock import org.mockito.kotlin.mock @OptIn(ExperimentalCoroutinesApi::class) @@ -71,9 +68,6 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() { private var tutorialScope = INTENT_TUTORIAL_SCOPE_TOUCHPAD private val viewModel by lazy { createViewModel(tutorialScope) } - // createUnsafe so its methods don't have to be called on Main thread - private val lifecycle = LifecycleRegistry.createUnsafe(mock(LifecycleOwner::class.java)) - @get:Rule val mainDispatcherRule = MainDispatcherRule(kosmos.testDispatcher) private fun createViewModel( @@ -88,7 +82,6 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() { mock<InputDeviceTutorialLogger>(), SavedStateHandle(mapOf(INTENT_TUTORIAL_SCOPE_KEY to scope)), ) - lifecycle.addObserver(viewModel) return viewModel } @@ -279,7 +272,7 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() { collectValues(viewModel.screen) // just to initialize viewModel peripheralsState(touchpadConnected = true) - lifecycle.handleLifecycleEvent(Event.ON_START) + viewModel.onStart(TestLifecycleOwner()) assertGesturesDisabled() } @@ -291,8 +284,8 @@ class KeyboardTouchpadTutorialViewModelTest : SysuiTestCase() { collectValues(viewModel.screen) peripheralsState(touchpadConnected = true) - lifecycle.handleLifecycleEvent(Event.ON_START) - lifecycle.handleLifecycleEvent(Event.ON_STOP) + viewModel.onStart(TestLifecycleOwner()) + viewModel.onStop(TestLifecycleOwner()) assertGesturesNotDisabled() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/OWNERS b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/OWNERS new file mode 100644 index 000000000000..2355c48158f7 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 1562219 +chrisgollner@google.com +jmokut@google.com
\ No newline at end of file diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapterTest.kt new file mode 100644 index 000000000000..f78c692ee4c2 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapterTest.kt @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.data.repository + +import android.app.role.RoleManager +import android.app.role.roleManager +import android.content.Context +import android.content.Intent +import android.content.mockedContext +import android.content.packageManager +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.hardware.input.AppLaunchData +import android.hardware.input.AppLaunchData.RoleData +import android.hardware.input.InputGestureData +import android.hardware.input.InputGestureData.createKeyTrigger +import android.view.KeyEvent.KEYCODE_A +import android.view.KeyEvent.META_ALT_ON +import android.view.KeyEvent.META_CTRL_ON +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.app.ResolverActivity +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyboard.shortcut.data.model.InternalGroupsSource +import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup +import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo +import com.android.systemui.keyboard.shortcut.inputGestureDataAdapter +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType +import com.android.systemui.kosmos.runTest +import com.android.systemui.res.R +import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.settings.userTracker +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + + +@SmallTest +@RunWith(AndroidJUnit4::class) +class InputGestureDataAdapterTest : SysuiTestCase() { + + private val kosmos = testKosmos().also { kosmos -> + kosmos.userTracker = FakeUserTracker(onCreateCurrentUserContext = { kosmos.mockedContext }) + } + private val adapter = kosmos.inputGestureDataAdapter + private val roleManager = kosmos.roleManager + private val packageManager: PackageManager = kosmos.packageManager + private val mockUserContext: Context = kosmos.mockedContext + private val intent: Intent = mock() + private val fakeResolverActivityInfo = + ActivityInfo().apply { name = ResolverActivity::class.qualifiedName } + private val fakeActivityInfo: ActivityInfo = + ActivityInfo().apply { + name = FAKE_ACTIVITY_NAME + icon = 0x1 + nonLocalizedLabel = TEST_SHORTCUT_LABEL + } + private val mockSelectorIntent: Intent = mock() + + @Before + fun setup() { + whenever(mockUserContext.packageManager).thenReturn(packageManager) + whenever(mockUserContext.getSystemService(RoleManager::class.java)).thenReturn(roleManager) + whenever(roleManager.isRoleAvailable(TEST_ROLE)).thenReturn(true) + whenever(roleManager.getDefaultApplication(TEST_ROLE)).thenReturn(TEST_ROLE_PACKAGE) + whenever(packageManager.getActivityInfo(any(), anyInt())).thenReturn(mock()) + whenever(packageManager.getLaunchIntentForPackage(TEST_ROLE_PACKAGE)).thenReturn(intent) + whenever(intent.selector).thenReturn(mockSelectorIntent) + whenever(mockSelectorIntent.categories).thenReturn(setOf(TEST_ACTIVITY_CATEGORY)) + } + + @Test + fun shortcutLabel_whenDefaultAppForCategoryIsNotSet_loadsLabelFromFirstAppMatchingIntent() = + kosmos.runTest { + setApiToRetrieveResolverActivity() + + val inputGestureData = buildInputGestureDataForAppLaunchShortcut() + val internalGroups = adapter.toInternalGroupSources(listOf(inputGestureData)) + val label = + internalGroups.firstOrNull()?.groups?.firstOrNull()?.items?.firstOrNull()?.label + + assertThat(label).isEqualTo(expectedShortcutLabelForFirstAppMatchingIntent) + } + + @Test + fun shortcutLabel_whenDefaultAppForCategoryIsSet_loadsLabelOfDefaultApp() { + kosmos.runTest { + setApiToRetrieveSpecificActivity() + + val inputGestureData = buildInputGestureDataForAppLaunchShortcut() + val internalGroups = adapter.toInternalGroupSources(listOf(inputGestureData)) + val label = + internalGroups.firstOrNull()?.groups?.firstOrNull()?.items?.firstOrNull()?.label + + assertThat(label).isEqualTo(TEST_SHORTCUT_LABEL) + } + } + + @Test + fun shortcutIcon_whenDefaultAppForCategoryIsSet_loadsIconOfDefaultApp() { + kosmos.runTest { + setApiToRetrieveSpecificActivity() + + val inputGestureData = buildInputGestureDataForAppLaunchShortcut() + val internalGroups = adapter.toInternalGroupSources(listOf(inputGestureData)) + val icon = + internalGroups.firstOrNull()?.groups?.firstOrNull()?.items?.firstOrNull()?.icon + + assertThat(icon).isNotNull() + } + } + + @Test + fun internalGroupSource_isCorrectlyConvertedWithSimpleInputGestureData() = + kosmos.runTest { + setApiToRetrieveResolverActivity() + + val inputGestureData = buildInputGestureDataForAppLaunchShortcut() + val internalGroups = adapter.toInternalGroupSources(listOf(inputGestureData)) + + assertThat(internalGroups).containsExactly( + InternalGroupsSource( + type = ShortcutCategoryType.AppCategories, + groups = listOf( + InternalKeyboardShortcutGroup( + label = APPLICATION_SHORTCUT_GROUP_LABEL, + items = listOf( + InternalKeyboardShortcutInfo( + label = expectedShortcutLabelForFirstAppMatchingIntent, + keycode = KEYCODE_A, + modifiers = META_CTRL_ON or META_ALT_ON, + isCustomShortcut = true + ) + ) + ) + ) + ) + ) + } + + private fun setApiToRetrieveResolverActivity() { + whenever(intent.resolveActivityInfo(eq(packageManager), anyInt())) + .thenReturn(fakeResolverActivityInfo) + } + + private fun setApiToRetrieveSpecificActivity() { + whenever(intent.resolveActivityInfo(eq(packageManager), anyInt())) + .thenReturn(fakeActivityInfo) + } + + + private fun buildInputGestureDataForAppLaunchShortcut( + keyCode: Int = KEYCODE_A, + modifiers: Int = META_CTRL_ON or META_ALT_ON, + appLaunchData: AppLaunchData = RoleData(TEST_ROLE) + ): InputGestureData { + return InputGestureData.Builder() + .setTrigger(createKeyTrigger(keyCode, modifiers)) + .setAppLaunchData(appLaunchData) + .build() + } + + private val expectedShortcutLabelForFirstAppMatchingIntent = + context.getString(R.string.keyboard_shortcut_group_applications_browser) + + private companion object { + private const val TEST_ROLE = "Test Browser Role" + private const val TEST_ROLE_PACKAGE = "test.browser.package" + private const val APPLICATION_SHORTCUT_GROUP_LABEL = "Applications" + private const val FAKE_ACTIVITY_NAME = "Fake activity" + private const val TEST_SHORTCUT_LABEL = "Test shortcut label" + private const val TEST_ACTIVITY_CATEGORY = Intent.CATEGORY_APP_BROWSER + } +} 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 75190e973c1b..7dc7016e5e74 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 @@ -40,7 +40,6 @@ import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand @@ -543,37 +542,20 @@ 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, "Split screen", - "Switch to app on left or above while using split screen", - ), - simpleShortcutCategory( - MultiTasking, - "Split screen", - "Use split screen with current app on the right", - ), - simpleShortcutCategory( - MultiTasking, - "Split screen", - "Switch to app on right or below while using split screen", + "Use split screen with app on the right", ), simpleShortcutCategory(System, "System controls", "Show shortcuts"), simpleShortcutCategory(System, "System controls", "View recent apps"), - simpleShortcutCategory(AppCategories, "Applications", "Calculator"), - simpleShortcutCategory(AppCategories, "Applications", "Calendar"), - simpleShortcutCategory(AppCategories, "Applications", "Browser"), - simpleShortcutCategory(AppCategories, "Applications", "Contacts"), - simpleShortcutCategory(AppCategories, "Applications", "Email"), - simpleShortcutCategory(AppCategories, "Applications", "Maps"), - simpleShortcutCategory(AppCategories, "Applications", "SMS"), ) val customInputGestureTypeHome = simpleInputGestureData(keyGestureType = KEY_GESTURE_TYPE_HOME) @@ -602,40 +584,13 @@ object TestShortcuts { keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT ), simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT - ), - simpleInputGestureData( keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT ), simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT - ), - simpleInputGestureData( keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER ), simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS), simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS - ), - simpleInputGestureData( - keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING - ), - simpleInputGestureData( keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER ), ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt index 77c615cce287..789b10b7830c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfigTest.kt @@ -25,7 +25,8 @@ import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.communalSceneRepository import com.android.systemui.communal.domain.interactor.communalInteractor -import com.android.systemui.communal.domain.interactor.setCommunalEnabled +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor +import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.andSceneContainer @@ -38,7 +39,6 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest -import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -48,7 +48,7 @@ import platform.test.runner.parameterized.Parameters @SmallTest @OptIn(ExperimentalCoroutinesApi::class) -@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON) +@EnableFlags(Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON, Flags.FLAG_GLANCEABLE_HUB_V2) @RunWith(ParameterizedAndroidJunit4::class) class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : SysuiTestCase() { private val kosmos = testKosmos() @@ -69,6 +69,7 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy context = context, communalInteractor = kosmos.communalInteractor, communalSceneRepository = kosmos.communalSceneRepository, + communalSettingsInteractor = kosmos.communalSettingsInteractor, sceneInteractor = kosmos.sceneInteractor, ) } @@ -76,28 +77,30 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test fun lockscreenState_whenGlanceableHubEnabled_returnsVisible() = testScope.runTest { - kosmos.setCommunalEnabled(true) + kosmos.setCommunalV2Enabled(true) runCurrent() val lockScreenState by collectLastValue(underTest.lockScreenState) - assertTrue(lockScreenState is KeyguardQuickAffordanceConfig.LockScreenState.Visible) + assertThat(lockScreenState) + .isInstanceOf(KeyguardQuickAffordanceConfig.LockScreenState.Visible::class.java) } @Test fun lockscreenState_whenGlanceableHubDisabled_returnsHidden() = testScope.runTest { - kosmos.setCommunalEnabled(false) + kosmos.setCommunalV2Enabled(false) val lockScreenState by collectLastValue(underTest.lockScreenState) runCurrent() - assertTrue(lockScreenState is KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + assertThat(lockScreenState) + .isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) } @Test fun pickerScreenState_whenGlanceableHubEnabled_returnsDefault() = testScope.runTest { - kosmos.setCommunalEnabled(true) + kosmos.setCommunalV2Enabled(true) runCurrent() assertThat(underTest.getPickerScreenState()) @@ -107,7 +110,7 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Test fun pickerScreenState_whenGlanceableHubDisabled_returnsDisabled() = testScope.runTest { - kosmos.setCommunalEnabled(false) + kosmos.setCommunalV2Enabled(false) runCurrent() assertThat( @@ -143,7 +146,8 @@ class GlanceableHubQuickAffordanceConfigTest(flags: FlagsParameterization?) : Sy @Parameters(name = "{0}") fun getParams(): List<FlagsParameterization> { return FlagsParameterization.allCombinationsOf( - Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON + Flags.FLAG_GLANCEABLE_HUB_SHORTCUT_BUTTON, + Flags.FLAG_GLANCEABLE_HUB_V2, ) .andSceneContainer() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt index 5e9badc58d8b..4dbe7c8bdb5a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.shadeTestUtil import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -171,8 +172,10 @@ class AodToLockscreenTransitionViewModelTest(flags: FlagsParameterization) : Sys // WHEN transition is cancelled repository.sendTransitionStep(step(.1f, TransitionState.CANCELED)) - // THEN alpha is immediately set to 1f (expected lockscreen alpha state) - assertThat(deviceEntryBackgroundViewAlpha).isEqualTo(1f) + // THEN alpha updates according to whether the scene framework is enabled (CANCELED is + // ignored when the scene framework is enabled). + assertThat(deviceEntryBackgroundViewAlpha) + .isEqualTo(if (SceneContainerFlag.isEnabled) 0f else 1f) } @Test @@ -195,14 +198,14 @@ class AodToLockscreenTransitionViewModelTest(flags: FlagsParameterization) : Sys private fun step( value: Float, - state: TransitionState = TransitionState.RUNNING + state: TransitionState = TransitionState.RUNNING, ): TransitionStep { return TransitionStep( from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN, value = value, transitionState = state, - ownerName = "AodToLockscreenTransitionViewModelTest" + ownerName = "AodToLockscreenTransitionViewModelTest", ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index d0da2e9671c0..576795d7e293 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.res.R +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.ShadeTestUtil import com.android.systemui.shade.shadeTestUtil import com.android.systemui.testKosmos @@ -178,11 +179,13 @@ class LockscreenToOccludedTransitionViewModelTest(flags: FlagsParameterization) ), testScope = testScope, ) - assertThat(values.size).isEqualTo(3) + assertThat(values.size).isEqualTo(if (SceneContainerFlag.isEnabled) 2 else 3) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } - // Cancel will reset the translation - assertThat(values[2]).isEqualTo(0) + // When the scene framework is not enabled, cancel will reset the translation + if (!SceneContainerFlag.isEnabled) { + assertThat(values.last()).isEqualTo(0f) + } } @Test @@ -242,8 +245,9 @@ class LockscreenToOccludedTransitionViewModelTest(flags: FlagsParameterization) // WHEN transition is canceled repository.sendTransitionStep(step(1f, TransitionState.CANCELED)) - // THEN alpha is immediately set to 0f - assertThat(actual).isEqualTo(0f) + // THEN alpha updates according to whether the scene framework is enabled (CANCELED is + // ignored when the scene framework is enabled). + assertThat(actual).isEqualTo(if (SceneContainerFlag.isEnabled) 1f else 0f) } private fun step( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt index 111b3b65c05d..4457d9b25ade 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt @@ -38,6 +38,7 @@ import com.android.systemui.qs.fgsManagerController import com.android.systemui.qs.panels.domain.interactor.tileSquishinessInteractor import com.android.systemui.qs.panels.ui.viewmodel.setConfigurationForMediaInRow import com.android.systemui.res.R +import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository @@ -436,6 +437,28 @@ class QSFragmentComposeViewModelTest : AbstractQSFragmentComposeViewModelTest() } } + @Test + fun qsVisibleAndAnyShadeVisible() = + with(kosmos) { + testScope.testWithinLifecycle { + underTest.isQsVisible = false + fakeShadeRepository.setLegacyExpandedOrAwaitingInputTransfer(false) + assertThat(underTest.isQsVisibleAndAnyShadeExpanded).isFalse() + + underTest.isQsVisible = true + fakeShadeRepository.setLegacyExpandedOrAwaitingInputTransfer(false) + assertThat(underTest.isQsVisibleAndAnyShadeExpanded).isFalse() + + underTest.isQsVisible = false + fakeShadeRepository.setLegacyExpandedOrAwaitingInputTransfer(true) + assertThat(underTest.isQsVisibleAndAnyShadeExpanded).isFalse() + + underTest.isQsVisible = true + fakeShadeRepository.setLegacyExpandedOrAwaitingInputTransfer(true) + assertThat(underTest.isQsVisibleAndAnyShadeExpanded).isTrue() + } + } + private fun TestScope.setMediaState(state: MediaState) { with(kosmos) { val activeMedia = state == ACTIVE_MEDIA diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryTest.kt new file mode 100644 index 000000000000..eef195b56188 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.data.repository + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType +import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class GridLayoutTypeRepositoryTest : SysuiTestCase() { + val kosmos = testKosmos() + + val underTest = kosmos.gridLayoutTypeRepository + + @Test + fun defaultType_paginated() = + kosmos.runTest { + val type by collectLastValue(underTest.defaultLayoutType) + + assertThat(type).isEqualTo(PaginatedGridLayoutType) + } + + @Test + fun dualShadeType_infinite() = + kosmos.runTest { + val type by collectLastValue(underTest.dualShadeLayoutType) + + assertThat(type).isEqualTo(InfiniteGridLayoutType) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt new file mode 100644 index 000000000000..b5915386b443 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.domain.interactor + +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType +import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType +import com.android.systemui.shade.data.repository.fakeShadeRepository +import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class GridLayoutTypeInteractorTest : SysuiTestCase() { + val kosmos = testKosmos() + + val Kosmos.underTest by Kosmos.Fixture { kosmos.gridLayoutTypeInteractor } + + @DisableFlags(DualShade.FLAG_NAME) + @Test + fun noDualShade_gridAlwaysPaginated() = + kosmos.runTest { + val type by collectLastValue(underTest.layout) + + fakeShadeRepository.setShadeLayoutWide(false) + assertThat(type).isEqualTo(PaginatedGridLayoutType) + + fakeShadeRepository.setShadeLayoutWide(true) + assertThat(type).isEqualTo(PaginatedGridLayoutType) + } + + @EnableFlags(DualShade.FLAG_NAME) + @Test + fun dualShade_gridAlwaysInfinite() = + kosmos.runTest { + val type by collectLastValue(underTest.layout) + + fakeShadeRepository.setShadeLayoutWide(false) + assertThat(type).isEqualTo(InfiniteGridLayoutType) + + fakeShadeRepository.setShadeLayoutWide(true) + assertThat(type).isEqualTo(InfiniteGridLayoutType) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt index ae7c44e9b146..8b9ae9a0606d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/EditTileListStateTest.kt @@ -39,7 +39,7 @@ class EditTileListStateTest : SysuiTestCase() { @Test fun startDrag_listHasSpacers() { - underTest.onStarted(TestEditTiles[0]) + underTest.onStarted(TestEditTiles[0], DragType.Add) // [ a ] [ b ] [ c ] [ X ] // [ Large D ] [ e ] [ X ] @@ -51,8 +51,8 @@ class EditTileListStateTest : SysuiTestCase() { @Test fun moveDrag_listChanges() { - underTest.onStarted(TestEditTiles[4]) - underTest.onMoved(3, false) + underTest.onStarted(TestEditTiles[4], DragType.Add) + underTest.onTargeting(3, false) // Tile E goes to index 3 // [ a ] [ b ] [ c ] [ e ] @@ -65,8 +65,8 @@ class EditTileListStateTest : SysuiTestCase() { fun moveDragOnSidesOfLargeTile_listChanges() { val draggedCell = TestEditTiles[4] - underTest.onStarted(draggedCell) - underTest.onMoved(4, true) + underTest.onStarted(draggedCell, DragType.Add) + underTest.onTargeting(4, true) // Tile E goes to the right side of tile D, list is unchanged // [ a ] [ b ] [ c ] [ X ] @@ -74,7 +74,7 @@ class EditTileListStateTest : SysuiTestCase() { assertThat(underTest.tiles.toStrings()) .isEqualTo(listOf("a", "b", "c", "spacer", "d", "e", "spacer")) - underTest.onMoved(4, false) + underTest.onTargeting(4, false) // Tile E goes to the left side of tile D, they swap positions // [ a ] [ b ] [ c ] [ e ] @@ -87,8 +87,8 @@ class EditTileListStateTest : SysuiTestCase() { fun moveNewTile_tileIsAdded() { val newTile = createEditTile("newTile", 2) - underTest.onStarted(newTile) - underTest.onMoved(5, false) + underTest.onStarted(newTile, DragType.Add) + underTest.onTargeting(5, false) // New tile goes to index 5 // [ a ] [ b ] [ c ] [ X ] @@ -102,7 +102,7 @@ class EditTileListStateTest : SysuiTestCase() { @Test fun movedTileOutOfBounds_tileDisappears() { - underTest.onStarted(TestEditTiles[0]) + underTest.onStarted(TestEditTiles[0], DragType.Add) underTest.movedOutOfBounds() assertThat(underTest.tiles.toStrings()).doesNotContain(TestEditTiles[0].tile.tileSpec.spec) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt index a9a527fb8df6..4891c9fb6def 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayoutTest.kt @@ -22,7 +22,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.testScope import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository import com.android.systemui.qs.panels.data.repository.defaultLargeTilesRepository -import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout +import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout import com.android.systemui.qs.panels.ui.viewmodel.MockTileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.testKosmos diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelTest.kt index 583db722a759..bbfa7e7a81ee 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelTest.kt @@ -21,6 +21,7 @@ import android.content.ComponentName import android.graphics.drawable.TestStubDrawable import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest +import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.common.shared.model.ContentDescription @@ -29,9 +30,12 @@ import com.android.systemui.common.shared.model.Text import com.android.systemui.common.ui.compose.toAnnotatedString import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.qs.FakeQSFactory import com.android.systemui.qs.FakeQSTile +import com.android.systemui.qs.QSEditEvent import com.android.systemui.qs.panels.data.repository.stockTilesRepository import com.android.systemui.qs.panels.domain.interactor.FakeTileAvailabilityInteractor import com.android.systemui.qs.panels.domain.interactor.tileAvailabilityInteractorsMap @@ -42,8 +46,10 @@ import com.android.systemui.qs.pipeline.data.repository.fakeInstalledTilesReposi import com.android.systemui.qs.pipeline.data.repository.fakeMinimumTilesRepository import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.metricSpec import com.android.systemui.qs.qsTileFactory import com.android.systemui.qs.shared.model.TileCategory +import com.android.systemui.qs.tiles.impl.airplane.qsAirplaneModeTileConfig import com.android.systemui.qs.tiles.impl.alarm.qsAlarmTileConfig import com.android.systemui.qs.tiles.impl.battery.qsBatterySaverTileConfig import com.android.systemui.qs.tiles.impl.flashlight.qsFlashlightTileConfig @@ -86,6 +92,7 @@ class EditModeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { qsFlashlightTileConfig, qsBatterySaverTileConfig, qsAlarmTileConfig, + qsAirplaneModeTileConfig, qsCameraSensorPrivacyToggleTileConfig, qsMicrophoneSensorPrivacyToggleTileConfig, ) @@ -116,7 +123,7 @@ class EditModeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { fakeInstalledTilesRepository.setInstalledServicesForUser( userTracker.userId, - listOf(serviceInfo1, serviceInfo2) + listOf(serviceInfo1, serviceInfo2), ) with(fakeQSTileConfigProvider) { configs.forEach { putConfig(it.tileSpec, it) } } @@ -424,10 +431,7 @@ class EditModeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { testScope.runTest { val tiles by collectLastValue(underTest.tiles) val currentTiles = - mutableListOf( - TileSpec.create("flashlight"), - TileSpec.create("airplane"), - ) + mutableListOf(TileSpec.create("flashlight"), TileSpec.create("airplane")) currentTilesInteractor.setTiles(currentTiles) assertThat(currentTiles.size).isLessThan(minNumberOfTiles) @@ -549,6 +553,156 @@ class EditModeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { } } + // UI EVENT TESTS + + @Test + fun startEditing_onlyOneEvent() = + kosmos.runTest { + underTest.startEditing() + underTest.startEditing() + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + + assertThat(uiEventLoggerFake[0].eventId).isEqualTo(QSEditEvent.QS_EDIT_OPEN.id) + } + + @Test + fun stopEditing_notEditing_noEvent() = + kosmos.runTest { + underTest.stopEditing() + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0) + } + + @Test + fun stopEditing_whenEditing_correctEvent() = + kosmos.runTest { + underTest.startEditing() + underTest.stopEditing() + + assertThat(uiEventLoggerFake[1].eventId).isEqualTo(QSEditEvent.QS_EDIT_CLOSED.id) + } + + @Test + fun addTile_correctPackageAndPosition() = + kosmos.runTest { + val flashlightTile = TileSpec.create("flashlight") + val airplaneTile = TileSpec.create("airplane") + val internetTile = TileSpec.create("internet") + val customTile = TileSpec.create(component2) + currentTilesInteractor.setTiles(listOf(flashlightTile)) + runCurrent() + + underTest.addTile(airplaneTile) + underTest.addTile(internetTile, position = 0) + underTest.addTile(customTile, position = 1) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(3) + + with(uiEventLoggerFake[0]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_ADD.id) + assertThat(packageName).isEqualTo(airplaneTile.metricSpec) + assertThat(position).isEqualTo(-1) + } + with(uiEventLoggerFake[1]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_ADD.id) + assertThat(packageName).isEqualTo(internetTile.metricSpec) + assertThat(position).isEqualTo(0) + } + with(uiEventLoggerFake[2]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_ADD.id) + assertThat(packageName).isEqualTo(customTile.metricSpec) + assertThat(position).isEqualTo(1) + } + } + + @Test + fun addTile_alreadyThere_usesMoveEvent() = + kosmos.runTest { + val flashlightTile = TileSpec.create("flashlight") + val airplaneTile = TileSpec.create("airplane") + val internetTile = TileSpec.create("internet") + currentTilesInteractor.setTiles(listOf(flashlightTile, airplaneTile, internetTile)) + runCurrent() + + underTest.addTile(flashlightTile) // adding at the end, should use correct position + underTest.addTile(internetTile, 0) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2) + + with(uiEventLoggerFake[0]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_MOVE.id) + assertThat(packageName).isEqualTo(flashlightTile.metricSpec) + // adding at the end, should use correct position + assertThat(position).isEqualTo(2) + } + with(uiEventLoggerFake[1]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_MOVE.id) + assertThat(packageName).isEqualTo(internetTile.metricSpec) + assertThat(position).isEqualTo(0) + } + } + + @Test + fun removeTileEvent() = + kosmos.runTest { + val flashlightTile = TileSpec.create("flashlight") + val airplaneTile = TileSpec.create("airplane") + val internetTile = TileSpec.create("internet") + currentTilesInteractor.setTiles(listOf(flashlightTile, airplaneTile, internetTile)) + runCurrent() + + underTest.removeTile(airplaneTile) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + + with(uiEventLoggerFake[0]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_REMOVE.id) + assertThat(packageName).isEqualTo(airplaneTile.metricSpec) + } + } + + @Test + fun setTiles_emitsCorrectOperation_individualOperations() = + kosmos.runTest { + val flashlightTile = TileSpec.create("flashlight") + val airplaneTile = TileSpec.create("airplane") + val internetTile = TileSpec.create("internet") + val alarmTile = TileSpec.create("alarm") + + currentTilesInteractor.setTiles(listOf(flashlightTile, airplaneTile, internetTile)) + runCurrent() + + // 0. Move flashlightTile to position 2 + underTest.setTiles(listOf(airplaneTile, internetTile, flashlightTile)) + runCurrent() + + // 1. Add alarm tile at position 1 + underTest.setTiles(listOf(airplaneTile, alarmTile, internetTile, flashlightTile)) + runCurrent() + + // 2. Remove internetTile + underTest.setTiles(listOf(airplaneTile, alarmTile, flashlightTile)) + runCurrent() + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(3) + + with(uiEventLoggerFake[0]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_MOVE.id) + assertThat(packageName).isEqualTo(flashlightTile.metricSpec) + assertThat(position).isEqualTo(2) + } + with(uiEventLoggerFake[1]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_ADD.id) + assertThat(packageName).isEqualTo(alarmTile.metricSpec) + assertThat(position).isEqualTo(1) + } + with(uiEventLoggerFake[2]) { + assertThat(eventId).isEqualTo(QSEditEvent.QS_EDIT_REMOVE.id) + assertThat(packageName).isEqualTo(internetTile.metricSpec) + } + } + companion object { private val drawable1 = TestStubDrawable("drawable1") private val appName1 = "App1" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelTest.kt index f2bfd729f74a..a8e390c25a4d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelTest.kt @@ -23,6 +23,7 @@ import com.android.systemui.classifier.fakeFalsingManager import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.editModeButtonViewModelFactory import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt index 869ab6c24fce..1fc1c0fd1e6b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt @@ -85,6 +85,24 @@ class TileSpecTest : SysuiTestCase() { assertThat(TileSpec.create("")).isEqualTo(TileSpec.Invalid) } + @Test + fun metricSpec_invalid() { + assertThat(TileSpec.Invalid.metricSpec).isEmpty() + } + + @Test + fun metricSpec_platform_specName() { + val tile = "spec" + assertThat(TileSpec.create(tile).metricSpec).isEqualTo(tile) + } + + @Test + fun metricSpec_custom_packageName() { + val componentName = ComponentName("test_pkg", "test_cls") + + assertThat(TileSpec.create(componentName).metricSpec).isEqualTo(componentName.packageName) + } + companion object { private const val CUSTOM_TILE_PREFIX = "custom(" } 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/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt index ef1ae093bcc9..fd9f5f02ee62 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicyTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.display.data.repository.display import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.testKosmos @@ -38,17 +39,31 @@ import org.junit.runner.RunWith class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope + private val keyguardRepository = kosmos.fakeKeyguardRepository private val displayRepository = kosmos.displayRepository - val underTest = StatusBarTouchShadeDisplayPolicy(displayRepository, testScope.backgroundScope) + + private fun createUnderTest( + shadeOnDefaultDisplayWhenLocked: Boolean = false + ): StatusBarTouchShadeDisplayPolicy { + return StatusBarTouchShadeDisplayPolicy( + displayRepository, + keyguardRepository, + testScope.backgroundScope, + shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked, + ) + } @Test fun displayId_defaultToDefaultDisplay() { + val underTest = createUnderTest() + assertThat(underTest.displayId.value).isEqualTo(Display.DEFAULT_DISPLAY) } @Test fun onStatusBarTouched_called_updatesDisplayId() = testScope.runTest { + val underTest = createUnderTest() val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) @@ -60,6 +75,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_notExistentDisplay_displayIdNotUpdated() = testScope.runTest { + val underTest = createUnderTest() val displayIds by collectValues(underTest.displayId) assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY)) @@ -72,6 +88,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { @Test fun onStatusBarTouched_afterDisplayRemoved_goesBackToDefaultDisplay() = testScope.runTest { + val underTest = createUnderTest() val displayId by collectLastValue(underTest.displayId) displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) @@ -83,4 +100,40 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() { assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) } + + @Test + fun onStatusBarTouched_afterKeyguardVisible_goesBackToDefaultDisplay() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + val displayId by collectLastValue(underTest.displayId) + + displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) + underTest.onStatusBarTouched(2) + + assertThat(displayId).isEqualTo(2) + + keyguardRepository.setKeyguardShowing(true) + + assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) + } + + @Test + fun onStatusBarTouched_afterKeyguardHides_goesBackToPreviousDisplay() = + testScope.runTest { + val underTest = createUnderTest(shadeOnDefaultDisplayWhenLocked = true) + val displayId by collectLastValue(underTest.displayId) + + displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL)) + underTest.onStatusBarTouched(2) + + assertThat(displayId).isEqualTo(2) + + keyguardRepository.setKeyguardShowing(true) + + assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) + + keyguardRepository.setKeyguardShowing(false) + + assertThat(displayId).isEqualTo(2) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt index a8d5c31873de..e93d0effe742 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt @@ -16,32 +16,26 @@ package com.android.systemui.shade.domain.interactor -import android.content.mockedContext import android.content.res.Configuration import android.content.res.mockResources import android.view.Display -import android.view.mockWindowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.scene.ui.view.mockShadeRootView import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository import com.android.systemui.testKosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.advanceUntilIdle import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.inOrder +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock -import org.mockito.kotlin.verifyNoMoreInteractions import org.mockito.kotlin.whenever -@OptIn(ExperimentalCoroutinesApi::class) @RunWith(AndroidJUnit4::class) @SmallTest class ShadeDisplaysInteractorTest : SysuiTestCase() { @@ -49,9 +43,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { private val shadeRootview = kosmos.mockShadeRootView private val positionRepository = kosmos.fakeShadeDisplaysRepository - private val shadeContext = kosmos.mockedContext - private val testScope = kosmos.testScope - private val shadeWm = kosmos.mockWindowManager + private val shadeContext = kosmos.mockedWindowContext private val resources = kosmos.mockResources private val configuration = mock<Configuration>() private val display = mock<Display>() @@ -66,8 +58,8 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { whenever(resources.configuration).thenReturn(configuration) whenever(shadeContext.displayId).thenReturn(0) - whenever(shadeContext.getSystemService(any())).thenReturn(shadeWm) whenever(shadeContext.resources).thenReturn(resources) + whenever(shadeContext.display).thenReturn(display) } @Test @@ -77,7 +69,7 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { underTest.start() - verifyNoMoreInteractions(shadeWm) + verify(shadeContext, never()).reparentToDisplay(any()) } @Test @@ -87,24 +79,6 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() { underTest.start() - inOrder(shadeWm).apply { - verify(shadeWm).removeView(eq(shadeRootview)) - verify(shadeWm).addView(eq(shadeRootview), any()) - } - } - - @Test - fun start_shadePositionChanges_removedThenAdded() { - whenever(display.displayId).thenReturn(0) - positionRepository.setDisplayId(0) - underTest.start() - - positionRepository.setDisplayId(1) - testScope.advanceUntilIdle() - - inOrder(shadeWm).apply { - verify(shadeWm).removeView(eq(shadeRootview)) - verify(shadeWm).addView(eq(shadeRootview), any()) - } + verify(shadeContext).reparentToDisplay(eq(1)) } } 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/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt index 3ebf9f72b5ff..a62d9d5ce62f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel @@ -163,6 +164,28 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test + @EnableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON, StatusBarConnectedDisplays.FLAG_NAME) + fun chip_positiveStartTime_notifIconAndConnectedDisplaysFlagOn_iconIsNotifIcon() = + testScope.runTest { + val latest by collectLastValue(underTest.chip) + + val notifKey = "testNotifKey" + repo.setOngoingCallState( + inCallModel(startTimeMs = 1000, notificationIcon = null, notificationKey = notifKey) + ) + + assertThat((latest as OngoingActivityChipModel.Shown).icon) + .isInstanceOf( + OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon::class.java + ) + val actualNotifKey = + (((latest as OngoingActivityChipModel.Shown).icon) + as OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon) + .notificationKey + assertThat(actualNotifKey).isEqualTo(notifKey) + } + + @Test @DisableFlags(FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON) fun chip_zeroStartTime_notifIconFlagOff_iconIsPhone() = testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt index e96dd16e9023..63efc55e1a09 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.chips.notification.domain.interactor +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -25,7 +26,10 @@ import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.notification.data.model.activeNotificationModel +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -43,7 +47,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { kosmos.runTest { val icon = mock<StatusBarIconView>() val startingNotif = - activeNotificationModel(key = "notif1", statusBarChipIcon = icon, whenTime = 5432) + activeNotificationModel( + key = "notif1", + statusBarChipIcon = icon, + whenTime = 5432, + promotedContent = PROMOTED_CONTENT, + ) val underTest = factory.create(startingNotif) @@ -60,7 +69,11 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val originalIconView = mock<StatusBarIconView>() val underTest = factory.create( - activeNotificationModel(key = "notif1", statusBarChipIcon = originalIconView) + activeNotificationModel( + key = "notif1", + statusBarChipIcon = originalIconView, + promotedContent = PROMOTED_CONTENT, + ) ) val latest by collectLastValue(underTest.notificationChip) @@ -71,6 +84,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { key = "notif1", statusBarChipIcon = newIconView, whenTime = 6543, + promotedContent = PROMOTED_CONTENT, ) ) @@ -85,14 +99,22 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val originalIconView = mock<StatusBarIconView>() val underTest = factory.create( - activeNotificationModel(key = "notif1", statusBarChipIcon = originalIconView) + activeNotificationModel( + key = "notif1", + statusBarChipIcon = originalIconView, + promotedContent = PROMOTED_CONTENT, + ) ) val latest by collectLastValue(underTest.notificationChip) val newIconView = mock<StatusBarIconView>() underTest.setNotification( - activeNotificationModel(key = "other_notif", statusBarChipIcon = newIconView) + activeNotificationModel( + key = "other_notif", + statusBarChipIcon = newIconView, + promotedContent = PROMOTED_CONTENT, + ) ) assertThat(latest!!.key).isEqualTo("notif1") @@ -100,10 +122,43 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { } @Test + fun notificationChip_ignoresSetWithNullPromotedContent() = + kosmos.runTest { + val originalIconView = mock<StatusBarIconView>() + val underTest = + factory.create( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = originalIconView, + promotedContent = PROMOTED_CONTENT, + ) + ) + + val latest by collectLastValue(underTest.notificationChip) + + val newIconView = mock<StatusBarIconView>() + underTest.setNotification( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = newIconView, + promotedContent = null, + ) + ) + + assertThat(latest!!.statusBarChipIconView).isEqualTo(originalIconView) + } + + @Test fun notificationChip_missingStatusBarIconChipView_inConstructor_emitsNull() = kosmos.runTest { val underTest = - factory.create(activeNotificationModel(key = "notif1", statusBarChipIcon = null)) + factory.create( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = null, + promotedContent = PROMOTED_CONTENT, + ) + ) val latest by collectLastValue(underTest.notificationChip) @@ -111,17 +166,104 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { } @Test + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun notificationChip_cdEnabled_missingStatusBarIconChipView_inConstructor_emitsNotNull() = + kosmos.runTest { + val underTest = + factory.create( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = null, + whenTime = 123L, + promotedContent = PROMOTED_CONTENT, + ) + ) + + val latest by collectLastValue(underTest.notificationChip) + + assertThat(latest) + .isEqualTo( + NotificationChipModel( + "notif1", + statusBarChipIconView = null, + whenTime = 123L, + promotedContent = PROMOTED_CONTENT, + ) + ) + } + + @Test fun notificationChip_missingStatusBarIconChipView_inSet_emitsNull() = kosmos.runTest { - val startingNotif = activeNotificationModel(key = "notif1", statusBarChipIcon = mock()) + val startingNotif = + activeNotificationModel( + key = "notif1", + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) + val underTest = factory.create(startingNotif) + val latest by collectLastValue(underTest.notificationChip) + assertThat(latest).isNotNull() + + underTest.setNotification( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = null, + promotedContent = PROMOTED_CONTENT, + ) + ) + + assertThat(latest).isNull() + } + + @Test + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun notificationChip_missingStatusBarIconChipView_inSet_cdEnabled_emitsNotNull() = + kosmos.runTest { + val startingNotif = + activeNotificationModel( + key = "notif1", + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) val underTest = factory.create(startingNotif) val latest by collectLastValue(underTest.notificationChip) assertThat(latest).isNotNull() underTest.setNotification( - activeNotificationModel(key = "notif1", statusBarChipIcon = null) + activeNotificationModel( + key = "notif1", + statusBarChipIcon = null, + whenTime = 123L, + promotedContent = PROMOTED_CONTENT, + ) ) + assertThat(latest) + .isEqualTo( + NotificationChipModel( + key = "notif1", + statusBarChipIconView = null, + whenTime = 123L, + promotedContent = PROMOTED_CONTENT, + ) + ) + } + + @Test + fun notificationChip_missingPromotedContent_inConstructor_emitsNull() = + kosmos.runTest { + val underTest = + factory.create( + activeNotificationModel( + key = "notif1", + statusBarChipIcon = mock(), + promotedContent = null, + ) + ) + + val latest by collectLastValue(underTest.notificationChip) + assertThat(latest).isNull() } @@ -132,7 +274,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val underTest = factory.create( - activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock()) + activeNotificationModel( + key = "notif", + uid = UID, + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) ) val latest by collectLastValue(underTest.notificationChip) @@ -147,7 +294,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { val underTest = factory.create( - activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock()) + activeNotificationModel( + key = "notif", + uid = UID, + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) ) val latest by collectLastValue(underTest.notificationChip) @@ -160,7 +312,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { kosmos.runTest { val underTest = factory.create( - activeNotificationModel(key = "notif", uid = UID, statusBarChipIcon = mock()) + activeNotificationModel( + key = "notif", + uid = UID, + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) ) val latest by collectLastValue(underTest.notificationChip) @@ -192,6 +349,7 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { key = "notif", uid = hiddenUid, statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, ) ) val latest by collectLastValue(underTest.notificationChip) @@ -200,7 +358,12 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { // WHEN the notif gets a new UID that starts as visible activityManagerRepository.fake.startingIsAppVisibleValue = true underTest.setNotification( - activeNotificationModel(key = "notif", uid = shownUid, statusBarChipIcon = mock()) + activeNotificationModel( + key = "notif", + uid = shownUid, + statusBarChipIcon = mock(), + promotedContent = PROMOTED_CONTENT, + ) ) // THEN we re-fetch the app visibility state with the new UID, and since that UID is @@ -210,5 +373,6 @@ class SingleNotificationChipInteractorTest : SysuiTestCase() { companion object { private const val UID = 885 + private val PROMOTED_CONTENT = PromotedNotificationContentModel.Builder("notif1").build() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt index 11831ca97389..b174fcee779c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt @@ -28,7 +28,9 @@ import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips +import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository @@ -107,6 +109,60 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun chips_onePromotedNotif_connectedDisplaysFlagEnabled_statusBarIconMatches() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + + val notifKey = "notif" + setNotifs( + listOf( + activeNotificationModel( + key = notifKey, + statusBarChipIcon = null, + promotedContent = PromotedNotificationContentModel.Builder(notifKey).build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + val chip = latest!![0] + assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java) + assertThat(chip.icon) + .isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(notifKey)) + } + + @Test + fun chips_onePromotedNotif_colorMatches() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.colors = + PromotedNotificationContentModel.Colors( + backgroundColor = 56, + primaryTextColor = 89, + ) + } + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = mock<StatusBarIconView>(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + val colors = latest!![0].colors + assertThat(colors).isInstanceOf(ColorsModel.Custom::class.java) + assertThat((colors as ColorsModel.Custom).backgroundColorInt).isEqualTo(56) + assertThat((colors as ColorsModel.Custom).primaryTextColorInt).isEqualTo(89) + } + + @Test fun chips_onlyForPromotedNotifs() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -139,6 +195,41 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun chips_connectedDisplaysFlagEnabled_onlyForPromotedNotifs() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + + val firstKey = "notif1" + val secondKey = "notif2" + val thirdKey = "notif3" + setNotifs( + listOf( + activeNotificationModel( + key = firstKey, + statusBarChipIcon = null, + promotedContent = PromotedNotificationContentModel.Builder(firstKey).build(), + ), + activeNotificationModel( + key = secondKey, + statusBarChipIcon = null, + promotedContent = + PromotedNotificationContentModel.Builder(secondKey).build(), + ), + activeNotificationModel( + key = thirdKey, + statusBarChipIcon = null, + promotedContent = null, + ), + ) + ) + + assertThat(latest).hasSize(2) + assertIsNotifKey(latest!![0], firstKey) + assertIsNotifKey(latest!![1], secondKey) + } + + @Test fun chips_clickingChipNotifiesInteractor() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -178,5 +269,12 @@ class NotifChipsViewModelTest : SysuiTestCase() { assertThat((latest as OngoingActivityChipModel.Shown).icon) .isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(expectedIcon)) } + + fun assertIsNotifKey(latest: OngoingActivityChipModel?, expectedKey: String) { + assertThat(latest) + .isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java) + assertThat((latest as OngoingActivityChipModel.Shown).icon) + .isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(expectedKey)) + } } } 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 689fc7cb647b..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 @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification @@ -22,671 +24,809 @@ import android.app.NotificationManager import android.os.UserHandle import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.service.notification.StatusBarNotification -import androidx.test.ext.junit.runners.AndroidJUnit4 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.dagger.qualifiers.Application +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.kosmos.applicationCoroutineScope -import com.android.systemui.plugins.statusbar.StatusBarStateController +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 +import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.DynamicPrivacyController import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder -import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable +import com.android.systemui.statusbar.notification.collection.notifPipeline +import com.android.systemui.statusbar.notification.dynamicPrivacyController +import com.android.systemui.statusbar.notification.mockDynamicPrivacyController import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.notificationLockscreenUserManager import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController +import com.android.systemui.statusbar.policy.mockSensitiveNotificationProtectionController +import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionController import com.android.systemui.testKosmos -import com.android.systemui.user.domain.interactor.SelectedUserInteractor -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.withArgCaptor -import dagger.BindsInstance -import dagger.Component -import kotlinx.coroutines.CoroutineScope +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.Mockito.never -import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) -class SensitiveContentCoordinatorTest : SysuiTestCase() { - - val kosmos = testKosmos() - - val dynamicPrivacyController: DynamicPrivacyController = mock() - val lockscreenUserManager: NotificationLockscreenUserManager = mock() - val pipeline: NotifPipeline = mock() - val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock() - val statusBarStateController: StatusBarStateController = mock() - val keyguardStateController: KeyguardStateController = mock() - val mSelectedUserInteractor: SelectedUserInteractor = mock() +@RunWith(ParameterizedAndroidJunit4::class) +class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestCase() { + + val kosmos = + testKosmos().apply { + // Override some Kosmos objects with mocks or fakes for easier testability + dynamicPrivacyController = mockDynamicPrivacyController + sensitiveNotificationProtectionController = + mockSensitiveNotificationProtectionController + statusBarStateController = fakeStatusBarStateController + } + + val testScope = kosmos.testScope + + val dynamicPrivacyController: DynamicPrivacyController = kosmos.mockDynamicPrivacyController + val lockscreenUserManager: NotificationLockscreenUserManager = + kosmos.notificationLockscreenUserManager + val pipeline: NotifPipeline = kosmos.notifPipeline + val keyguardUpdateMonitor: KeyguardUpdateMonitor = kosmos.keyguardUpdateMonitor + val statusBarStateController: SysuiStatusBarStateController = + kosmos.fakeStatusBarStateController val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController = - mock() - val deviceEntryInteractor: DeviceEntryInteractor = mock() - val sceneInteractor: SceneInteractor = mock() - - val coordinator: SensitiveContentCoordinator = - DaggerTestSensitiveContentCoordinatorComponent.factory() - .create( - dynamicPrivacyController, - lockscreenUserManager, - keyguardUpdateMonitor, - statusBarStateController, - keyguardStateController, - mSelectedUserInteractor, - sensitiveNotificationProtectionController, - deviceEntryInteractor, - sceneInteractor, - kosmos.applicationCoroutineScope, - ) - .coordinator + kosmos.mockSensitiveNotificationProtectionController + val deviceEntryInteractor: DeviceEntryInteractor + get() = kosmos.deviceEntryInteractor - @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 faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository + val sceneInteractor: SceneInteractor + get() = kosmos.sceneInteractor - val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() - invalidator.setInvalidationListener(invalidationListener) + val coordinator: SensitiveContentCoordinator by lazy { kosmos.sensitiveContentCoordinator } - dynamicPrivacyListener.onDynamicPrivacyChanged() + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf().andSceneContainer() + } + } - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + init { + mSetFlagsRule.setFlagsParameterization(flags) } @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) + @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()) + } - onSensitiveStateChangedListener.run() + @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()) + } - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) - } + @Test + @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) + 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(NotifFilter::class.java)) - } + 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()) + } - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(statusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD) - whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any())) - .thenReturn(true) - val entry = fakeNotification(2, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - whenever(sensitiveNotificationProtectionController.shouldProtectNotification(any())) - .thenReturn(true) - - 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) + } + } + + 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 { @@ -733,26 +873,3 @@ class SensitiveContentCoordinatorTest : SysuiTestCase() { return notificationEntry } } - -@CoordinatorScope -@Component(modules = [SensitiveContentCoordinatorModule::class]) -interface TestSensitiveContentCoordinatorComponent { - val coordinator: SensitiveContentCoordinator - - @Component.Factory - interface Factory { - fun create( - @BindsInstance dynamicPrivacyController: DynamicPrivacyController, - @BindsInstance lockscreenUserManager: NotificationLockscreenUserManager, - @BindsInstance keyguardUpdateMonitor: KeyguardUpdateMonitor, - @BindsInstance statusBarStateController: StatusBarStateController, - @BindsInstance keyguardStateController: KeyguardStateController, - @BindsInstance selectedUserInteractor: SelectedUserInteractor, - @BindsInstance - sensitiveNotificationProtectionController: SensitiveNotificationProtectionController, - @BindsInstance deviceEntryInteractor: DeviceEntryInteractor, - @BindsInstance sceneInteractor: SceneInteractor, - @BindsInstance @Application scope: CoroutineScope, - ): TestSensitiveContentCoordinatorComponent - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java index c9ca67e6af94..615f4b01df9b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java @@ -78,7 +78,7 @@ public class FooterViewTest extends SysuiTestCase { public void setUp() { if (NotifRedesignFooter.isEnabled()) { mView = (FooterView) LayoutInflater.from(mSpyContext).inflate( - R.layout.status_bar_notification_footer_redesign, null, false); + R.layout.notification_2025_footer, null, false); } else { mView = (FooterView) LayoutInflater.from(mSpyContext).inflate( R.layout.status_bar_notification_footer, null, false); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt deleted file mode 100644 index 8b4f53a88a6f..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.statusbar.notification.headsup - -import android.app.Notification -import android.app.PendingIntent -import android.app.Person -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.testing.TestableLooper.RunWithLooper -import androidx.test.filters.SmallTest -import com.android.internal.logging.testing.UiEventLoggerFake -import com.android.systemui.SysuiTestCase -import com.android.systemui.dump.DumpManager -import com.android.systemui.kosmos.KosmosJavaAdapter -import com.android.systemui.log.logcatLogBuffer -import com.android.systemui.res.R -import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder -import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl -import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl.HeadsUpEntry -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper -import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.concurrency.mockExecutorHandler -import com.android.systemui.util.kotlin.JavaAdapter -import com.android.systemui.util.settings.FakeGlobalSettings -import com.android.systemui.util.time.FakeSystemClock -import com.google.common.truth.Truth -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.flow.MutableStateFlow -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.invocation.InvocationOnMock -import org.mockito.junit.MockitoJUnit -import org.mockito.junit.MockitoRule -import org.mockito.kotlin.eq -import platform.test.runner.parameterized.ParameterizedAndroidJunit4 -import platform.test.runner.parameterized.Parameters - -@SmallTest -@RunWithLooper -@RunWith(ParameterizedAndroidJunit4::class) -// TODO(b/378142453): Merge this with HeadsUpManagerImplTest. -open class HeadsUpManagerImplOldTest(flags: FlagsParameterization?) : SysuiTestCase() { - protected var mKosmos: KosmosJavaAdapter = KosmosJavaAdapter(this) - - @JvmField @Rule var rule: MockitoRule = MockitoJUnit.rule() - - private val mUiEventLoggerFake = UiEventLoggerFake() - - private val mLogger: HeadsUpManagerLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer())) - - @Mock private val mBgHandler: Handler? = null - - @Mock private val dumpManager: DumpManager? = null - - @Mock private val mShadeInteractor: ShadeInteractor? = null - private var mAvalancheController: AvalancheController? = null - - @Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null - - protected val globalSettings: FakeGlobalSettings = FakeGlobalSettings() - protected val systemClock: FakeSystemClock = FakeSystemClock() - protected val executor: FakeExecutor = FakeExecutor(systemClock) - - @Mock protected var mRow: ExpandableNotificationRow? = null - - private fun createHeadsUpManager(): HeadsUpManagerImpl { - return HeadsUpManagerImpl( - mContext, - mLogger, - mKosmos.statusBarStateController, - mKosmos.keyguardBypassController, - GroupMembershipManagerImpl(), - mKosmos.visualStabilityProvider, - mKosmos.configurationController, - mockExecutorHandler(executor), - globalSettings, - systemClock, - executor, - mAccessibilityMgr, - mUiEventLoggerFake, - JavaAdapter(mKosmos.testScope), - mShadeInteractor, - mAvalancheController, - ) - } - - private fun createStickyEntry(id: Int): NotificationEntry { - val notif = - Notification.Builder(mContext, "") - .setSmallIcon(R.drawable.ic_person) - .setFullScreenIntent( - Mockito.mock(PendingIntent::class.java), /* highPriority */ - true, - ) - .build() - return HeadsUpManagerTestUtil.createEntry(id, notif) - } - - private fun createStickyForSomeTimeEntry(id: Int): NotificationEntry { - val notif = - Notification.Builder(mContext, "") - .setSmallIcon(R.drawable.ic_person) - .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) - .build() - return HeadsUpManagerTestUtil.createEntry(id, notif) - } - - private fun useAccessibilityTimeout(use: Boolean) { - if (use) { - Mockito.doReturn(TEST_A11Y_AUTO_DISMISS_TIME) - .`when`(mAccessibilityMgr!!) - .getRecommendedTimeoutMillis(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()) - } else { - Mockito.`when`( - mAccessibilityMgr!!.getRecommendedTimeoutMillis( - ArgumentMatchers.anyInt(), - ArgumentMatchers.anyInt(), - ) - ) - .then { i: InvocationOnMock -> i.getArgument(0) } - } - } - - init { - mSetFlagsRule.setFlagsParameterization(flags!!) - } - - @Throws(Exception::class) - override fun SysuiSetup() { - super.SysuiSetup() - mContext.getOrCreateTestableResources().apply { - this.addOverride(R.integer.ambient_notification_extension_time, TEST_EXTENSION_TIME) - this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME) - this.addOverride( - R.integer.heads_up_notification_minimum_time, - TEST_MINIMUM_DISPLAY_TIME, - ) - this.addOverride( - R.integer.heads_up_notification_minimum_time_with_throttling, - TEST_MINIMUM_DISPLAY_TIME, - ) - this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME) - this.addOverride( - R.integer.sticky_heads_up_notification_time, - TEST_STICKY_AUTO_DISMISS_TIME, - ) - } - - mAvalancheController = - AvalancheController(dumpManager!!, mUiEventLoggerFake, mLogger, mBgHandler!!) - Mockito.`when`(mShadeInteractor!!.isAnyExpanded).thenReturn(MutableStateFlow(true)) - Mockito.`when`(mKosmos.keyguardBypassController.bypassEnabled).thenReturn(false) - } - - @Test - fun testHasNotifications_headsUpManagerMapNotEmpty_true() { - val bhum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - bhum.showNotification(entry) - - Truth.assertThat(bhum.mHeadsUpEntryMap).isNotEmpty() - Truth.assertThat(bhum.hasNotifications()).isTrue() - } - - @Test - @EnableFlags(NotificationThrottleHun.FLAG_NAME) - fun testHasNotifications_avalancheMapNotEmpty_true() { - val bhum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - val headsUpEntry = bhum.createHeadsUpEntry(notifEntry) - mAvalancheController!!.addToNext(headsUpEntry) {} - - Truth.assertThat(mAvalancheController!!.getWaitingEntryList()).isNotEmpty() - Truth.assertThat(bhum.hasNotifications()).isTrue() - } - - @Test - @EnableFlags(NotificationThrottleHun.FLAG_NAME) - fun testHasNotifications_false() { - val bhum = createHeadsUpManager() - Truth.assertThat(bhum.mHeadsUpEntryMap).isEmpty() - Truth.assertThat(mAvalancheController!!.getWaitingEntryList()).isEmpty() - Truth.assertThat(bhum.hasNotifications()).isFalse() - } - - @Test - @EnableFlags(NotificationThrottleHun.FLAG_NAME) - fun testGetHeadsUpEntryList_includesAvalancheEntryList() { - val bhum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - val headsUpEntry = bhum.createHeadsUpEntry(notifEntry) - mAvalancheController!!.addToNext(headsUpEntry) {} - - Truth.assertThat(bhum.headsUpEntryList).contains(headsUpEntry) - } - - @Test - @EnableFlags(NotificationThrottleHun.FLAG_NAME) - fun testGetHeadsUpEntry_returnsAvalancheEntry() { - val bhum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - val headsUpEntry = bhum.createHeadsUpEntry(notifEntry) - mAvalancheController!!.addToNext(headsUpEntry) {} - - Truth.assertThat(bhum.getHeadsUpEntry(notifEntry.key)).isEqualTo(headsUpEntry) - } - - @Test - fun testShowNotification_addsEntry() { - val alm = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - alm.showNotification(entry) - - assertThat(alm.isHeadsUpEntry(entry.key)).isTrue() - assertThat(alm.hasNotifications()).isTrue() - assertThat(alm.getEntry(entry.key)).isEqualTo(entry) - } - - @Test - fun testShowNotification_autoDismisses() { - val alm = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - alm.showNotification(entry) - systemClock.advanceTime((TEST_AUTO_DISMISS_TIME * 3 / 2).toLong()) - - assertThat(alm.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testRemoveNotification_removeDeferred() { - val alm = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - alm.showNotification(entry) - - val removedImmediately = - alm.removeNotification(entry.key, /* releaseImmediately= */ false, "removeDeferred") - assertThat(removedImmediately).isFalse() - assertThat(alm.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testRemoveNotification_forceRemove() { - val alm = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - alm.showNotification(entry) - - val removedImmediately = - alm.removeNotification(entry.key, /* releaseImmediately= */ true, "forceRemove") - assertThat(removedImmediately).isTrue() - assertThat(alm.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testReleaseAllImmediately() { - val alm = createHeadsUpManager() - for (i in 0 until TEST_NUM_NOTIFICATIONS) { - val entry = HeadsUpManagerTestUtil.createEntry(i, mContext) - entry.row = mRow - alm.showNotification(entry) - } - - alm.releaseAllImmediately() - - assertThat(alm.allEntries.count()).isEqualTo(0) - } - - @Test - fun testCanRemoveImmediately_notShownLongEnough() { - val alm = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - alm.showNotification(entry) - - // The entry has just been added so we should not remove immediately. - assertThat(alm.canRemoveImmediately(entry.key)).isFalse() - } - - @Test - fun testHunRemovedLogging() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - val headsUpEntry = Mockito.mock(HeadsUpEntry::class.java) - Mockito.`when`(headsUpEntry.pinnedStatus) - .thenReturn(MutableStateFlow(PinnedStatus.NotPinned)) - headsUpEntry.mEntry = notifEntry - - hum.onEntryRemoved(headsUpEntry, "test") - - Mockito.verify(mLogger, Mockito.times(1)).logNotificationActuallyRemoved(eq(notifEntry)) - } - - @Test - fun testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - systemClock.advanceTime((TEST_TOUCH_ACCEPTANCE_TIME / 2 + TEST_AUTO_DISMISS_TIME).toLong()) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testShowNotification_autoDismissesWithDefaultTimeout() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - systemClock.advanceTime( - (TEST_TOUCH_ACCEPTANCE_TIME + - (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) - .toLong() - ) - - assertThat(hum.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() { - val hum = createHeadsUpManager() - val entry = createStickyForSomeTimeEntry(/* id= */ 0) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - systemClock.advanceTime( - (TEST_TOUCH_ACCEPTANCE_TIME + - (TEST_AUTO_DISMISS_TIME + TEST_STICKY_AUTO_DISMISS_TIME) / 2) - .toLong() - ) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testShowNotification_sticky_neverAutoDismisses() { - val hum = createHeadsUpManager() - val entry = createStickyEntry(/* id= */ 0) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - systemClock.advanceTime( - (TEST_TOUCH_ACCEPTANCE_TIME + 2 * TEST_A11Y_AUTO_DISMISS_TIME).toLong() - ) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testShowNotification_autoDismissesWithAccessibilityTimeout() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - useAccessibilityTimeout(true) - - hum.showNotification(entry) - systemClock.advanceTime( - (TEST_TOUCH_ACCEPTANCE_TIME + - (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) - .toLong() - ) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() { - val hum = createHeadsUpManager() - val entry = createStickyForSomeTimeEntry(/* id= */ 0) - useAccessibilityTimeout(true) - - hum.showNotification(entry) - systemClock.advanceTime( - (TEST_TOUCH_ACCEPTANCE_TIME + - (TEST_STICKY_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) - .toLong() - ) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - } - - @Test - fun testRemoveNotification_beforeMinimumDisplayTime() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - - val removedImmediately = - hum.removeNotification( - entry.key, - /* releaseImmediately = */ false, - "beforeMinimumDisplayTime", - ) - assertThat(removedImmediately).isFalse() - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - - systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) - - assertThat(hum.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testRemoveNotification_afterMinimumDisplayTime() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - useAccessibilityTimeout(false) - - hum.showNotification(entry) - systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) - - assertThat(hum.isHeadsUpEntry(entry.key)).isTrue() - - val removedImmediately = - hum.removeNotification( - entry.key, - /* releaseImmediately = */ false, - "afterMinimumDisplayTime", - ) - assertThat(removedImmediately).isTrue() - assertThat(hum.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testRemoveNotification_releaseImmediately() { - val hum = createHeadsUpManager() - val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - hum.showNotification(entry) - - val removedImmediately = - hum.removeNotification( - entry.key, - /* releaseImmediately = */ true, - "afterMinimumDisplayTime", - ) - assertThat(removedImmediately).isTrue() - assertThat(hum.isHeadsUpEntry(entry.key)).isFalse() - } - - @Test - fun testIsSticky_rowPinnedAndExpanded_true() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - Mockito.`when`(mRow!!.isPinned).thenReturn(true) - notifEntry.row = mRow - - hum.showNotification(notifEntry) - - val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key) - headsUpEntry!!.setExpanded(true) - - assertThat(hum.isSticky(notifEntry.key)).isTrue() - } - - @Test - fun testIsSticky_remoteInputActive_true() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - hum.showNotification(notifEntry) - - val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key) - headsUpEntry!!.mRemoteInputActive = true - - assertThat(hum.isSticky(notifEntry.key)).isTrue() - } - - @Test - fun testIsSticky_hasFullScreenIntent_true() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) - - hum.showNotification(notifEntry) - - assertThat(hum.isSticky(notifEntry.key)).isTrue() - } - - @Test - fun testIsSticky_stickyForSomeTime_false() { - val hum = createHeadsUpManager() - val entry = createStickyForSomeTimeEntry(/* id= */ 0) - - hum.showNotification(entry) - - assertThat(hum.isSticky(entry.key)).isFalse() - } - - @Test - fun testIsSticky_false() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - hum.showNotification(notifEntry) - - val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key) - headsUpEntry!!.setExpanded(false) - headsUpEntry.mRemoteInputActive = false - - assertThat(hum.isSticky(notifEntry.key)).isFalse() - } - - @Test - fun testCompareTo_withNullEntries() { - val hum = createHeadsUpManager() - val alertEntry = NotificationEntryBuilder().setTag("alert").build() - - hum.showNotification(alertEntry) - - assertThat(hum.compare(alertEntry, null)).isLessThan(0) - assertThat(hum.compare(null, alertEntry)).isGreaterThan(0) - assertThat(hum.compare(null, null)).isEqualTo(0) - } - - @Test - fun testCompareTo_withNonAlertEntries() { - val hum = createHeadsUpManager() - - val nonAlertEntry1 = NotificationEntryBuilder().setTag("nae1").build() - val nonAlertEntry2 = NotificationEntryBuilder().setTag("nae2").build() - val alertEntry = NotificationEntryBuilder().setTag("alert").build() - hum.showNotification(alertEntry) - - assertThat(hum.compare(alertEntry, nonAlertEntry1)).isLessThan(0) - assertThat(hum.compare(nonAlertEntry1, alertEntry)).isGreaterThan(0) - assertThat(hum.compare(nonAlertEntry1, nonAlertEntry2)).isEqualTo(0) - } - - @Test - fun testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() { - val hum = createHeadsUpManager() - - val ongoingCall = - hum.HeadsUpEntry( - NotificationEntryBuilder() - .setSbn( - HeadsUpManagerTestUtil.createSbn( - /* id = */ 0, - Notification.Builder(mContext, "") - .setCategory(Notification.CATEGORY_CALL) - .setOngoing(true), - ) - ) - .build() - ) - - val activeRemoteInput = - hum.HeadsUpEntry(HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)) - activeRemoteInput.mRemoteInputActive = true - - assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0) - assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0) - } - - @Test - fun testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() { - val hum = createHeadsUpManager() - - val person = Person.Builder().setName("person").build() - val intent = Mockito.mock(PendingIntent::class.java) - val incomingCall = - hum.HeadsUpEntry( - NotificationEntryBuilder() - .setSbn( - HeadsUpManagerTestUtil.createSbn( - /* id = */ 0, - Notification.Builder(mContext, "") - .setStyle( - Notification.CallStyle.forIncomingCall(person, intent, intent) - ), - ) - ) - .build() - ) - - val activeRemoteInput = - hum.HeadsUpEntry(HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)) - activeRemoteInput.mRemoteInputActive = true - - assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0) - assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0) - } - - @Test - @EnableFlags(NotificationThrottleHun.FLAG_NAME) - fun testPinEntry_logsPeek_throttleEnabled() { - val hum = createHeadsUpManager() - - // Needs full screen intent in order to be pinned - val entryToPin = - hum.HeadsUpEntry( - HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) - ) - - // Note: the standard way to show a notification would be calling showNotification rather - // than onAlertEntryAdded. However, in practice showNotification in effect adds - // the notification and then updates it; in order to not log twice, the entry needs - // to have a functional ExpandableNotificationRow that can keep track of whether it's - // pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit. - hum.onEntryAdded(entryToPin) - - assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(2) - assertThat(AvalancheController.ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN.getId()) - .isEqualTo(mUiEventLoggerFake.eventId(0)) - assertThat(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.id) - .isEqualTo(mUiEventLoggerFake.eventId(1)) - } - - @Test - @DisableFlags(NotificationThrottleHun.FLAG_NAME) - fun testPinEntry_logsPeek_throttleDisabled() { - val hum = createHeadsUpManager() - - // Needs full screen intent in order to be pinned - val entryToPin = - hum.HeadsUpEntry( - HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) - ) - - // Note: the standard way to show a notification would be calling showNotification rather - // than onAlertEntryAdded. However, in practice showNotification in effect adds - // the notification and then updates it; in order to not log twice, the entry needs - // to have a functional ExpandableNotificationRow that can keep track of whether it's - // pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit. - hum.onEntryAdded(entryToPin) - - assertThat(mUiEventLoggerFake.numLogs()).isEqualTo(1) - assertThat(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.id) - .isEqualTo(mUiEventLoggerFake.eventId(0)) - } - - @Test - fun testSetUserActionMayIndirectlyRemove() { - val hum = createHeadsUpManager() - val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) - - hum.showNotification(notifEntry) - - assertThat(hum.canRemoveImmediately(notifEntry.key)).isFalse() - - hum.setUserActionMayIndirectlyRemove(notifEntry) - - assertThat(hum.canRemoveImmediately(notifEntry.key)).isTrue() - } - - companion object { - const val TEST_TOUCH_ACCEPTANCE_TIME: Int = 200 - const val TEST_A11Y_AUTO_DISMISS_TIME: Int = 1000 - const val TEST_EXTENSION_TIME = 500 - - const val TEST_MINIMUM_DISPLAY_TIME: Int = 400 - const val TEST_AUTO_DISMISS_TIME: Int = 600 - const val TEST_STICKY_AUTO_DISMISS_TIME: Int = 800 - - // Number of notifications to use in tests requiring multiple notifications - private const val TEST_NUM_NOTIFICATIONS = 4 - - init { - Truth.assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME) - Truth.assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME) - Truth.assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME) - } - - @get:Parameters(name = "{0}") - @JvmStatic - val flags: List<FlagsParameterization> - get() = FlagsParameterization.allCombinationsOf(NotificationThrottleHun.FLAG_NAME) - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt index a5fecb8d0e8d..8420c49755b1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt @@ -15,25 +15,38 @@ */ package com.android.systemui.statusbar.notification.headsup +import android.app.Notification +import android.app.PendingIntent +import android.app.Person 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.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper +import android.view.accessibility.accessibilityManager import android.view.accessibility.accessibilityManagerWrapper import androidx.test.filters.SmallTest import com.android.internal.logging.uiEventLoggerFake +import com.android.systemui.SysuiTestCase +import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.dump.dumpManager +import com.android.systemui.flags.BrokenWithSceneContainer import com.android.systemui.flags.andSceneContainer import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher -import com.android.systemui.log.logcatLogBuffer import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shadeTestUtil import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager +import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl.HeadsUpEntry +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationTestHelper import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun import com.android.systemui.statusbar.phone.keyguardBypassController import com.android.systemui.statusbar.policy.configurationController @@ -41,12 +54,19 @@ import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.testKosmos import com.android.systemui.util.concurrency.mockExecutorHandler import com.android.systemui.util.kotlin.JavaAdapter +import com.android.systemui.util.settings.fakeGlobalSettings +import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +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 @@ -54,19 +74,26 @@ import platform.test.runner.parameterized.Parameters @SmallTest @RunWith(ParameterizedAndroidJunit4::class) @RunWithLooper -class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplOldTest(flags) { - - private val headsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer()) +class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { + init { + mSetFlagsRule.setFlagsParameterization(flags) + } private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val testScope = kosmos.testScope private val groupManager = mock<GroupMembershipManager>() private val bgHandler = mock<Handler>() + private val headsUpManagerLogger = mock<HeadsUpManagerLogger>() val statusBarStateController = kosmos.sysuiStatusBarStateController + private val globalSettings = kosmos.fakeGlobalSettings + private val systemClock = kosmos.fakeSystemClock + private val executor = kosmos.fakeExecutor + private val uiEventLoggerFake = kosmos.uiEventLoggerFake private val javaAdapter: JavaAdapter = JavaAdapter(testScope.backgroundScope) + private lateinit var testHelper: NotificationTestHelper private lateinit var avalancheController: AvalancheController private lateinit var underTest: HeadsUpManagerImpl @@ -90,12 +117,15 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO ) } + allowTestableLooperAsMainThread() + testHelper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)) + whenever(kosmos.keyguardBypassController.bypassEnabled).thenReturn(false) kosmos.visualStabilityProvider.isReorderingAllowed = true avalancheController = AvalancheController( kosmos.dumpManager, - kosmos.uiEventLoggerFake, + uiEventLoggerFake, headsUpManagerLogger, bgHandler, ) @@ -113,7 +143,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO systemClock, executor, kosmos.accessibilityManagerWrapper, - kosmos.uiEventLoggerFake, + uiEventLoggerFake, javaAdapter, kosmos.shadeInteractor, avalancheController, @@ -121,6 +151,220 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO } @Test + fun testHasNotifications_headsUpManagerMapNotEmpty_true() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + underTest.showNotification(entry) + + assertThat(underTest.mHeadsUpEntryMap).isNotEmpty() + assertThat(underTest.hasNotifications()).isTrue() + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + fun testHasNotifications_avalancheMapNotEmpty_true() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + val headsUpEntry = underTest.createHeadsUpEntry(notifEntry) + avalancheController.addToNext(headsUpEntry) {} + + assertThat(avalancheController.getWaitingEntryList()).isNotEmpty() + assertThat(underTest.hasNotifications()).isTrue() + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + fun testHasNotifications_false() { + assertThat(underTest.mHeadsUpEntryMap).isEmpty() + assertThat(avalancheController.getWaitingEntryList()).isEmpty() + assertThat(underTest.hasNotifications()).isFalse() + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + fun testGetHeadsUpEntryList_includesAvalancheEntryList() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + val headsUpEntry = underTest.createHeadsUpEntry(notifEntry) + avalancheController.addToNext(headsUpEntry) {} + + assertThat(underTest.headsUpEntryList).contains(headsUpEntry) + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + fun testGetHeadsUpEntry_returnsAvalancheEntry() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + val headsUpEntry = underTest.createHeadsUpEntry(notifEntry) + avalancheController.addToNext(headsUpEntry) {} + + assertThat(underTest.getHeadsUpEntry(notifEntry.key)).isEqualTo(headsUpEntry) + } + + @Test + fun testShowNotification_addsEntry() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + assertThat(underTest.hasNotifications()).isTrue() + assertThat(underTest.getEntry(entry.key)).isEqualTo(entry) + } + + @Test + fun testShowNotification_autoDismisses() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + systemClock.advanceTime((TEST_AUTO_DISMISS_TIME * 3 / 2).toLong()) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + fun testRemoveNotification_removeDeferred() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately= */ false, + "removeDeferred", + ) + assertThat(removedImmediately).isFalse() + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testRemoveNotification_forceRemove() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + + val removedImmediately = + underTest.removeNotification(entry.key, /* releaseImmediately= */ true, "forceRemove") + assertThat(removedImmediately).isTrue() + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + fun testReleaseAllImmediately() { + for (i in 0 until 4) { + val entry = HeadsUpManagerTestUtil.createEntry(i, mContext) + entry.row = mock<ExpandableNotificationRow>() + underTest.showNotification(entry) + } + + underTest.releaseAllImmediately() + + assertThat(underTest.allEntries.count()).isEqualTo(0) + } + + @Test + fun testCanRemoveImmediately_notShownLongEnough() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + + // The entry has just been added so we should not remove immediately. + assertThat(underTest.canRemoveImmediately(entry.key)).isFalse() + } + + @Test + fun testHunRemovedLogging() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + val headsUpEntry = underTest.HeadsUpEntry(notifEntry) + headsUpEntry.setRowPinnedStatus(PinnedStatus.NotPinned) + + underTest.onEntryRemoved(headsUpEntry, "test") + + verify(headsUpManagerLogger, times(1)).logNotificationActuallyRemoved(eq(notifEntry)) + } + + @Test + fun testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + systemClock.advanceTime((TEST_TOUCH_ACCEPTANCE_TIME / 2 + TEST_AUTO_DISMISS_TIME).toLong()) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testShowNotification_autoDismissesWithDefaultTimeout() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + systemClock.advanceTime( + (TEST_TOUCH_ACCEPTANCE_TIME + + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) + .toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + fun testRemoveNotification_beforeMinimumDisplayTime() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately = */ false, + "beforeMinimumDisplayTime", + ) + assertThat(removedImmediately).isFalse() + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + + systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + fun testRemoveNotification_afterMinimumDisplayTime() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately = */ false, + "afterMinimumDisplayTime", + ) + assertThat(removedImmediately).isTrue() + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + fun testRemoveNotification_releaseImmediately() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(entry) + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately = */ true, + "afterMinimumDisplayTime", + ) + assertThat(removedImmediately).isTrue() + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test fun testSnooze() { val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) underTest.showNotification(entry) @@ -160,7 +404,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO fun testCanRemoveImmediately_notTopEntry() { val earlierEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) val laterEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext) - laterEntry.row = mRow + laterEntry.row = mock<ExpandableNotificationRow>() underTest.showNotification(earlierEntry) underTest.showNotification(laterEntry) @@ -226,6 +470,122 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO } @Test + fun testShowNotification_sticky_neverAutoDismisses() { + val entry = createStickyEntry(id = 0) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + systemClock.advanceTime( + (TEST_TOUCH_ACCEPTANCE_TIME + 2 * TEST_A11Y_AUTO_DISMISS_TIME).toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testShowNotification_autoDismissesWithAccessibilityTimeout() { + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + useAccessibilityTimeout(true) + + underTest.showNotification(entry) + systemClock.advanceTime( + (TEST_TOUCH_ACCEPTANCE_TIME + + (TEST_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) + .toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testShowNotification_stickyForSomeTime_autoDismissesWithStickyTimeout() { + val entry = createStickyForSomeTimeEntry(id = 0) + useAccessibilityTimeout(false) + + underTest.showNotification(entry) + systemClock.advanceTime( + (TEST_TOUCH_ACCEPTANCE_TIME + + (TEST_AUTO_DISMISS_TIME + TEST_STICKY_AUTO_DISMISS_TIME) / 2) + .toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testShowNotification_stickyForSomeTime_autoDismissesWithAccessibilityTimeout() { + val entry = createStickyForSomeTimeEntry(id = 0) + useAccessibilityTimeout(true) + + underTest.showNotification(entry) + systemClock.advanceTime( + (TEST_TOUCH_ACCEPTANCE_TIME + + (TEST_STICKY_AUTO_DISMISS_TIME + TEST_A11Y_AUTO_DISMISS_TIME) / 2) + .toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + } + + @Test + fun testIsSticky_rowPinnedAndExpanded_true() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + val row = testHelper.createRow() + row.setPinnedStatus(PinnedStatus.PinnedBySystem) + notifEntry.row = row + + underTest.showNotification(notifEntry) + + val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key) + headsUpEntry!!.setExpanded(true) + + assertThat(underTest.isSticky(notifEntry.key)).isTrue() + } + + @Test + fun testIsSticky_remoteInputActive_true() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(notifEntry) + + val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key) + headsUpEntry!!.mRemoteInputActive = true + + assertThat(underTest.isSticky(notifEntry.key)).isTrue() + } + + @Test + fun testIsSticky_hasFullScreenIntent_true() { + val notifEntry = HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) + + underTest.showNotification(notifEntry) + + assertThat(underTest.isSticky(notifEntry.key)).isTrue() + } + + @Test + fun testIsSticky_stickyForSomeTime_false() { + val entry = createStickyForSomeTimeEntry(id = 0) + + underTest.showNotification(entry) + + assertThat(underTest.isSticky(entry.key)).isFalse() + } + + @Test + fun testIsSticky_false() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(notifEntry) + + val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key) + headsUpEntry!!.setExpanded(false) + headsUpEntry.mRemoteInputActive = false + + assertThat(underTest.isSticky(notifEntry.key)).isFalse() + } + + @Test fun testShouldHeadsUpBecomePinned_noFSI_false() = kosmos.runTest { statusBarStateController.setState(StatusBarState.KEYGUARD) @@ -270,11 +630,13 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO } @Test + @BrokenWithSceneContainer(381869885) // because `ShadeTestUtil.setShadeExpansion(0f)` + // still causes `ShadeInteractor.isAnyExpanded` to emit `true`, when it should emit `false`. fun shouldHeadsUpBecomePinned_shadeNotExpanded_true() = kosmos.runTest { // GIVEN - shadeTestUtil.setShadeExpansion(0f) - // TODO(b/381869885): Determine why we need both of these ShadeTestUtil calls. + // TODO(b/381869885): We should be able to use `ShadeTestUtil.setShadeExpansion(0f)` + // instead. shadeTestUtil.setLegacyExpandedOrAwaitingInputTransfer(false) val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) @@ -347,8 +709,183 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : HeadsUpManagerImplO assertThat(underTest.shouldHeadsUpBecomePinned(entry)).isFalse() } + @Test + fun testCompareTo_withNullEntries() { + val alertEntry = NotificationEntryBuilder().setTag("alert").build() + + underTest.showNotification(alertEntry) + + assertThat(underTest.compare(alertEntry, null)).isLessThan(0) + assertThat(underTest.compare(null, alertEntry)).isGreaterThan(0) + assertThat(underTest.compare(null, null)).isEqualTo(0) + } + + @Test + fun testCompareTo_withNonAlertEntries() { + val nonAlertEntry1 = NotificationEntryBuilder().setTag("nae1").build() + val nonAlertEntry2 = NotificationEntryBuilder().setTag("nae2").build() + val alertEntry = NotificationEntryBuilder().setTag("alert").build() + underTest.showNotification(alertEntry) + + assertThat(underTest.compare(alertEntry, nonAlertEntry1)).isLessThan(0) + assertThat(underTest.compare(nonAlertEntry1, alertEntry)).isGreaterThan(0) + assertThat(underTest.compare(nonAlertEntry1, nonAlertEntry2)).isEqualTo(0) + } + + @Test + fun testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() { + val ongoingCall = + underTest.HeadsUpEntry( + NotificationEntryBuilder() + .setSbn( + HeadsUpManagerTestUtil.createSbn( + /* id = */ 0, + Notification.Builder(mContext, "") + .setCategory(Notification.CATEGORY_CALL) + .setOngoing(true), + ) + ) + .build() + ) + + val activeRemoteInput = + underTest.HeadsUpEntry(HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)) + activeRemoteInput.mRemoteInputActive = true + + assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0) + assertThat(activeRemoteInput.compareTo(ongoingCall)).isGreaterThan(0) + } + + @Test + fun testAlertEntryCompareTo_incomingCallLessThanActiveRemoteInput() { + val person = Person.Builder().setName("person").build() + val intent = mock<PendingIntent>() + val incomingCall = + underTest.HeadsUpEntry( + NotificationEntryBuilder() + .setSbn( + HeadsUpManagerTestUtil.createSbn( + /* id = */ 0, + Notification.Builder(mContext, "") + .setStyle( + Notification.CallStyle.forIncomingCall(person, intent, intent) + ), + ) + ) + .build() + ) + + val activeRemoteInput = + underTest.HeadsUpEntry(HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)) + activeRemoteInput.mRemoteInputActive = true + + assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0) + assertThat(activeRemoteInput.compareTo(incomingCall)).isGreaterThan(0) + } + + @Test + @EnableFlags(NotificationThrottleHun.FLAG_NAME) + fun testPinEntry_logsPeek_throttleEnabled() { + // Needs full screen intent in order to be pinned + val entryToPin = + underTest.HeadsUpEntry( + HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) + ) + + // Note: the standard way to show a notification would be calling showNotification rather + // than onAlertEntryAdded. However, in practice showNotification in effect adds + // the notification and then updates it; in order to not log twice, the entry needs + // to have a functional ExpandableNotificationRow that can keep track of whether it's + // pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit. + underTest.onEntryAdded(entryToPin) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2) + assertThat(AvalancheController.ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN.getId()) + .isEqualTo(uiEventLoggerFake.eventId(0)) + assertThat(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.id) + .isEqualTo(uiEventLoggerFake.eventId(1)) + } + + @Test + @DisableFlags(NotificationThrottleHun.FLAG_NAME) + fun testPinEntry_logsPeek_throttleDisabled() { + // Needs full screen intent in order to be pinned + val entryToPin = + underTest.HeadsUpEntry( + HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext) + ) + + // Note: the standard way to show a notification would be calling showNotification rather + // than onAlertEntryAdded. However, in practice showNotification in effect adds + // the notification and then updates it; in order to not log twice, the entry needs + // to have a functional ExpandableNotificationRow that can keep track of whether it's + // pinned or not (via isRowPinned()). That feels like a lot to pull in to test this one bit. + underTest.onEntryAdded(entryToPin) + + assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1) + assertThat(HeadsUpManagerImpl.NotificationPeekEvent.NOTIFICATION_PEEK.id) + .isEqualTo(uiEventLoggerFake.eventId(0)) + } + + @Test + fun testSetUserActionMayIndirectlyRemove() { + val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + + underTest.showNotification(notifEntry) + + assertThat(underTest.canRemoveImmediately(notifEntry.key)).isFalse() + + underTest.setUserActionMayIndirectlyRemove(notifEntry) + + assertThat(underTest.canRemoveImmediately(notifEntry.key)).isTrue() + } + + private fun createStickyEntry(id: Int): NotificationEntry { + val notif = + Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setFullScreenIntent(mock<PendingIntent>(), /* highPriority= */ true) + .build() + return HeadsUpManagerTestUtil.createEntry(id, notif) + } + + private fun createStickyForSomeTimeEntry(id: Int): NotificationEntry { + val notif = + Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) + .build() + return HeadsUpManagerTestUtil.createEntry(id, notif) + } + + private fun useAccessibilityTimeout(use: Boolean) { + if (use) { + whenever(kosmos.accessibilityManager.getRecommendedTimeoutMillis(any(), any())) + .thenReturn(TEST_A11Y_AUTO_DISMISS_TIME) + } else { + doAnswer { it.getArgument(0) as Int } + .whenever(kosmos.accessibilityManager) + .getRecommendedTimeoutMillis(any(), any()) + } + } + companion object { + const val TEST_TOUCH_ACCEPTANCE_TIME = 200 + const val TEST_A11Y_AUTO_DISMISS_TIME = 1000 + const val TEST_EXTENSION_TIME = 500 + + const val TEST_MINIMUM_DISPLAY_TIME = 400 + const val TEST_AUTO_DISMISS_TIME = 600 + const val TEST_STICKY_AUTO_DISMISS_TIME = 800 + + init { + assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME) + assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME) + assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME) + } + @get:Parameters(name = "{0}") + @JvmStatic val flags: List<FlagsParameterization> get() = buildList { addAll( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt index 46c360aecd48..be20bc1bf9d4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt @@ -225,16 +225,12 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati val displayId = 123 darkIconRepository.darkState(displayId).value = SysuiDarkIconDispatcher.DarkChange(emptyList(), 0f, 0xAABBCC) - val iconColorsLookup by collectLastValue(underTest.iconColors(displayId)) - assertThat(iconColorsLookup).isNotNull() - - val iconColors = iconColorsLookup?.iconColors(Rect()) + val iconColors by collectLastValue(underTest.iconColors(displayId)) assertThat(iconColors).isNotNull() - iconColors!! - assertThat(iconColors.tint).isEqualTo(0xAABBCC) + assertThat(iconColors!!.tint).isEqualTo(0xAABBCC) - val staticDrawableColor = iconColors.staticDrawableColor(Rect()) + val staticDrawableColor = iconColors!!.staticDrawableColor(Rect()) assertThat(staticDrawableColor).isEqualTo(0xAABBCC) } @@ -245,8 +241,7 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati val displayId = 321 darkIconRepository.darkState(displayId).value = SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC) - val iconColorsLookup by collectLastValue(underTest.iconColors(displayId)) - val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4)) + val iconColors by collectLastValue(underTest.iconColors(displayId)) val staticDrawableColor = iconColors?.staticDrawableColor(Rect(6, 6, 7, 7)) assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) } @@ -257,9 +252,9 @@ class NotificationIconContainerStatusBarViewModelTest(flags: FlagsParameterizati val displayId = 987 darkIconRepository.darkState(displayId).value = SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC) - val iconColorsLookup by collectLastValue(underTest.iconColors(displayId)) - val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7)) - assertThat(iconColors).isNull() + val iconColors by collectLastValue(underTest.iconColors(displayId)) + assertThat(iconColors!!.staticDrawableColor(Rect(6, 6, 7, 7))) + .isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt index 9f98fd4c8508..5a5ec90a5f44 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt @@ -21,9 +21,8 @@ import android.testing.TestableLooper.RunWithLooper import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.settingslib.Utils -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R import com.android.systemui.statusbar.notification.FakeShadowView import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.SourceType @@ -62,8 +61,8 @@ class ActivatableNotificationViewTest : SysuiTestCase() { } as T? } - mNormalColor = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorSurfaceContainerHigh) + mNormalColor = + mContext.getColor(com.android.internal.R.color.materialColorSurfaceContainerHigh) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index f76f1ce48a5c..7f139bd69a37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -30,6 +30,8 @@ import android.content.ComponentName; import android.os.PowerManager; import android.os.UserHandle; import android.os.Vibrator; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.view.HapticFeedbackConstants; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -45,6 +47,8 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.QSPanelController; +import com.android.systemui.qs.flags.QSComposeFragment; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.CameraLauncher; @@ -54,15 +58,14 @@ import com.android.systemui.shade.ShadeHeaderController; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; +import com.android.systemui.shade.shared.flag.DualShade; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import dagger.Lazy; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -72,6 +75,8 @@ import org.mockito.stubbing.Answer; import java.util.Optional; +import dagger.Lazy; + @SmallTest @RunWith(AndroidJUnit4.class) public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { @@ -105,6 +110,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { @Mock private ActivityStarter mActivityStarter; @Mock private EmergencyGestureIntentFactory mEmergencyGestureIntentFactory; @Mock private KeyguardInteractor mKeyguardInteractor; + @Mock private QSPanelController mQSPanelController; CentralSurfacesCommandQueueCallbacks mSbcqCallbacks; @@ -150,6 +156,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); when(mRemoteInputQuickSettingsDisabler.adjustDisableFlags(anyInt())) .thenAnswer((Answer<Integer>) invocation -> invocation.getArgument(0)); + when(mCentralSurfaces.getQSPanelController()).thenReturn(mQSPanelController); } @Test @@ -230,4 +237,45 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { verify(mQSHost).addTile(c, false); } + + @Test + @DisableFlags(value = {QSComposeFragment.FLAG_NAME, DualShade.FLAG_NAME}) + public void clickQsTile_flagsDisabled_callsQSPanelController() { + ComponentName c = new ComponentName("testpkg", "testcls"); + + mSbcqCallbacks.clickTile(c); + verify(mQSPanelController).clickTile(c); + } + + @Test + @DisableFlags(DualShade.FLAG_NAME) + @EnableFlags(QSComposeFragment.FLAG_NAME) + public void clickQsTile_onlyQSComposeFlag_callsQSHost() { + ComponentName c = new ComponentName("testpkg", "testcls"); + + mSbcqCallbacks.clickTile(c); + verify(mQSPanelController, never()).clickTile(c); + verify(mQSHost).clickTile(c); + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + @DisableFlags(QSComposeFragment.FLAG_NAME) + public void clickQsTile_onlyDualShadeFlag_callsQSHost() { + ComponentName c = new ComponentName("testpkg", "testcls"); + + mSbcqCallbacks.clickTile(c); + verify(mQSPanelController, never()).clickTile(c); + verify(mQSHost).clickTile(c); + } + + @Test + @EnableFlags(value = {QSComposeFragment.FLAG_NAME, DualShade.FLAG_NAME}) + public void clickQsTile_qsComposeAndDualShadeFlags_callsQSHost() { + ComponentName c = new ComponentName("testpkg", "testcls"); + + mSbcqCallbacks.clickTile(c); + verify(mQSPanelController, never()).clickTile(c); + verify(mQSHost).clickTile(c); + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java deleted file mode 100644 index 41782a123f14..000000000000 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import static android.view.Display.DEFAULT_DISPLAY; - -import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE; -import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PEEK; -import static com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Notification; -import android.app.PendingIntent; -import android.app.StatusBarManager; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; -import android.testing.TestableLooper; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import com.android.systemui.InitController; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.power.domain.interactor.PowerInteractor; -import com.android.systemui.settings.FakeDisplayTracker; -import com.android.systemui.shade.NotificationShadeWindowView; -import com.android.systemui.shade.QuickSettingsController; -import com.android.systemui.shade.ShadeController; -import com.android.systemui.shade.ShadeViewController; -import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.LockscreenShadeTransitionController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; -import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource; -import com.android.systemui.statusbar.notification.domain.interactor.NotificationAlertsInteractor; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; -import com.android.systemui.statusbar.notification.interruption.VisualInterruptionCondition; -import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider; -import com.android.systemui.statusbar.notification.interruption.VisualInterruptionFilter; -import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor; -import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; -import com.android.systemui.statusbar.policy.KeyguardStateController; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.List; -import java.util.Set; - -@SmallTest -@RunWith(AndroidJUnit4.class) -@RunWithLooper() -public class StatusBarNotificationPresenterTest extends SysuiTestCase { - private StatusBarNotificationPresenter mStatusBarNotificationPresenter; - private final VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider = - mock(VisualInterruptionDecisionProvider.class); - private NotificationInterruptSuppressor mInterruptSuppressor; - private VisualInterruptionCondition mAlertsDisabledCondition; - private VisualInterruptionCondition mVrModeCondition; - private VisualInterruptionFilter mNeedsRedactionFilter; - private VisualInterruptionCondition mPanelsDisabledCondition; - private CommandQueue mCommandQueue; - private final ShadeController mShadeController = mock(ShadeController.class); - private final NotificationAlertsInteractor mNotificationAlertsInteractor = - mock(NotificationAlertsInteractor.class); - private final KeyguardStateController mKeyguardStateController = - mock(KeyguardStateController.class); - - @Before - public void setup() { - mCommandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext)); - mDependency.injectTestDependency(StatusBarStateController.class, - mock(SysuiStatusBarStateController.class)); - mDependency.injectTestDependency(ShadeController.class, mShadeController); - mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class); - mDependency.injectMockDependency(NotificationShadeWindowController.class); - - when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(true); - - createPresenter(); - if (VisualInterruptionRefactor.isEnabled()) { - verifyAndCaptureSuppressors(); - } else { - verifyAndCaptureLegacySuppressor(); - } - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testInit_refactorDisabled() { - assertFalse(VisualInterruptionRefactor.isEnabled()); - assertNull(mAlertsDisabledCondition); - assertNull(mVrModeCondition); - assertNull(mNeedsRedactionFilter); - assertNull(mPanelsDisabledCondition); - assertNotNull(mInterruptSuppressor); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testInit_refactorEnabled() { - assertTrue(VisualInterruptionRefactor.isEnabled()); - assertNotNull(mAlertsDisabledCondition); - assertNotNull(mVrModeCondition); - assertNotNull(mNeedsRedactionFilter); - assertNotNull(mPanelsDisabledCondition); - assertNull(mInterruptSuppressor); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testNoSuppressHeadsUp_default_refactorDisabled() { - assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(createNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testNoSuppressHeadsUp_default_refactorEnabled() { - assertFalse(mAlertsDisabledCondition.shouldSuppress()); - assertFalse(mVrModeCondition.shouldSuppress()); - assertFalse(mNeedsRedactionFilter.shouldSuppress(createNotificationEntry())); - assertFalse(mAlertsDisabledCondition.shouldSuppress()); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressHeadsUp_disabledStatusBar_refactorDisabled() { - mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0, - false /* animate */); - TestableLooper.get(this).processAllMessages(); - - assertTrue("The panel should suppress heads up while disabled", - mInterruptSuppressor.suppressAwakeHeadsUp(createNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressHeadsUp_disabledStatusBar_refactorEnabled() { - mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0, - false /* animate */); - TestableLooper.get(this).processAllMessages(); - - assertTrue("The panel should suppress heads up while disabled", - mPanelsDisabledCondition.shouldSuppress()); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressHeadsUp_disabledNotificationShade_refactorDisabled() { - mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, - false /* animate */); - TestableLooper.get(this).processAllMessages(); - - assertTrue("The panel should suppress interruptions while notification shade disabled", - mInterruptSuppressor.suppressAwakeHeadsUp(createNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressHeadsUp_disabledNotificationShade_refactorEnabled() { - mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE, - false /* animate */); - TestableLooper.get(this).processAllMessages(); - - assertTrue("The panel should suppress interruptions while notification shade disabled", - mPanelsDisabledCondition.shouldSuppress()); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testPanelsDisabledConditionSuppressesPeek() { - final Set<VisualInterruptionType> types = mPanelsDisabledCondition.getTypes(); - assertTrue(types.contains(PEEK)); - assertFalse(types.contains(PULSE)); - assertFalse(types.contains(BUBBLE)); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorDisabled() { - when(mKeyguardStateController.isShowing()).thenReturn(true); - when(mKeyguardStateController.isOccluded()).thenReturn(false); - - assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(createFsiNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorEnabled() { - when(mKeyguardStateController.isShowing()).thenReturn(true); - when(mKeyguardStateController.isOccluded()).thenReturn(false); - - assertFalse(mNeedsRedactionFilter.shouldSuppress(createFsiNotificationEntry())); - - final Set<VisualInterruptionType> types = mNeedsRedactionFilter.getTypes(); - assertTrue(types.contains(PEEK)); - assertFalse(types.contains(PULSE)); - assertFalse(types.contains(BUBBLE)); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressInterruptions_vrMode_refactorDisabled() { - mStatusBarNotificationPresenter.mVrMode = true; - - assertTrue("Vr mode should suppress interruptions", - mInterruptSuppressor.suppressAwakeInterruptions(createNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressInterruptions_vrMode_refactorEnabled() { - mStatusBarNotificationPresenter.mVrMode = true; - - assertTrue("Vr mode should suppress interruptions", mVrModeCondition.shouldSuppress()); - - final Set<VisualInterruptionType> types = mVrModeCondition.getTypes(); - assertTrue(types.contains(PEEK)); - assertFalse(types.contains(PULSE)); - assertTrue(types.contains(BUBBLE)); - } - - @Test - @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressInterruptions_statusBarAlertsDisabled_refactorDisabled() { - when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false); - - assertTrue("When alerts aren't enabled, interruptions are suppressed", - mInterruptSuppressor.suppressInterruptions(createNotificationEntry())); - } - - @Test - @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) - public void testSuppressInterruptions_statusBarAlertsDisabled_refactorEnabled() { - when(mNotificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false); - - assertTrue("When alerts aren't enabled, interruptions are suppressed", - mAlertsDisabledCondition.shouldSuppress()); - - final Set<VisualInterruptionType> types = mAlertsDisabledCondition.getTypes(); - assertTrue(types.contains(PEEK)); - assertTrue(types.contains(PULSE)); - assertTrue(types.contains(BUBBLE)); - } - - private void createPresenter() { - final ShadeViewController shadeViewController = mock(ShadeViewController.class); - - final NotificationShadeWindowView notificationShadeWindowView = - mock(NotificationShadeWindowView.class); - when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); - - NotificationStackScrollLayoutController stackScrollLayoutController = - mock(NotificationStackScrollLayoutController.class); - when(stackScrollLayoutController.getView()).thenReturn( - mock(NotificationStackScrollLayout.class)); - - final InitController initController = new InitController(); - - mStatusBarNotificationPresenter = new StatusBarNotificationPresenter( - mContext, - shadeViewController, - mock(PanelExpansionInteractor.class), - mock(QuickSettingsController.class), - mock(HeadsUpManager.class), - notificationShadeWindowView, - mock(ActivityStarter.class), - stackScrollLayoutController, - mock(DozeScrimController.class), - mock(NotificationShadeWindowController.class), - mock(DynamicPrivacyController.class), - mKeyguardStateController, - mNotificationAlertsInteractor, - mock(LockscreenShadeTransitionController.class), - mock(PowerInteractor.class), - mCommandQueue, - mock(NotificationLockscreenUserManager.class), - mock(SysuiStatusBarStateController.class), - mock(NotifShadeEventSource.class), - mock(NotificationMediaManager.class), - mock(NotificationGutsManager.class), - initController, - mVisualInterruptionDecisionProvider, - mock(NotificationRemoteInputManager.class), - mock(NotificationRemoteInputManager.Callback.class), - mock(NotificationListContainer.class)); - - initController.executePostInitTasks(); - } - - private void verifyAndCaptureSuppressors() { - mInterruptSuppressor = null; - - final ArgumentCaptor<VisualInterruptionCondition> conditionCaptor = - ArgumentCaptor.forClass(VisualInterruptionCondition.class); - verify(mVisualInterruptionDecisionProvider, times(3)).addCondition( - conditionCaptor.capture()); - final List<VisualInterruptionCondition> conditions = conditionCaptor.getAllValues(); - mAlertsDisabledCondition = conditions.get(0); - mVrModeCondition = conditions.get(1); - mPanelsDisabledCondition = conditions.get(2); - - final ArgumentCaptor<VisualInterruptionFilter> needsRedactionFilterCaptor = - ArgumentCaptor.forClass(VisualInterruptionFilter.class); - verify(mVisualInterruptionDecisionProvider).addFilter(needsRedactionFilterCaptor.capture()); - mNeedsRedactionFilter = needsRedactionFilterCaptor.getValue(); - } - - private void verifyAndCaptureLegacySuppressor() { - mAlertsDisabledCondition = null; - mVrModeCondition = null; - mNeedsRedactionFilter = null; - mPanelsDisabledCondition = null; - - final ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor = - ArgumentCaptor.forClass(NotificationInterruptSuppressor.class); - verify(mVisualInterruptionDecisionProvider).addLegacySuppressor(suppressorCaptor.capture()); - mInterruptSuppressor = suppressorCaptor.getValue(); - } - - private NotificationEntry createNotificationEntry() { - return new NotificationEntryBuilder() - .setPkg("a") - .setOpPkg("a") - .setTag("a") - .setNotification(new Notification.Builder(getContext(), "a").build()) - .build(); - } - - private NotificationEntry createFsiNotificationEntry() { - final Notification notification = new Notification.Builder(getContext(), "a") - .setFullScreenIntent(mock(PendingIntent.class), true) - .build(); - - return new NotificationEntryBuilder() - .setPkg("a") - .setOpPkg("a") - .setTag("a") - .setNotification(notification) - .build(); - } -} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt new file mode 100644 index 000000000000..31fbcb984105 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.phone + +import android.app.Notification +import android.app.Notification.Builder +import android.app.StatusBarManager +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.testing.TestableLooper +import android.testing.TestableLooper.RunWithLooper +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.InitController +import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.activityStarter +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.settings.FakeDisplayTracker +import com.android.systemui.shade.NotificationShadeWindowView +import com.android.systemui.shade.ShadeController +import com.android.systemui.shade.ShadeViewController +import com.android.systemui.shade.domain.interactor.panelExpansionInteractor +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.NotificationRemoteInputManager +import com.android.systemui.statusbar.NotificationShadeWindowController +import com.android.systemui.statusbar.lockscreenShadeTransitionController +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.domain.interactor.NotificationAlertsInteractor +import com.android.systemui.statusbar.notification.dynamicPrivacyController +import com.android.systemui.statusbar.notification.headsup.headsUpManager +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionCondition +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionFilter +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor +import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController +import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.statusbar.notificationRemoteInputManager +import com.android.systemui.statusbar.notificationShadeWindowController +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.statusbar.sysuiStatusBarStateController +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import com.google.common.truth.Truth.assertWithMessage +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper +class StatusBarNotificationPresenterTest : SysuiTestCase() { + private val kosmos = testKosmos() + + private val visualInterruptionDecisionProvider: VisualInterruptionDecisionProvider = mock() + + private var interruptSuppressor: NotificationInterruptSuppressor? = null + private var alertsDisabledCondition: VisualInterruptionCondition? = null + private var vrModeCondition: VisualInterruptionCondition? = null + private var needsRedactionFilter: VisualInterruptionFilter? = null + private var panelsDisabledCondition: VisualInterruptionCondition? = null + + private val commandQueue: CommandQueue = CommandQueue(mContext, FakeDisplayTracker(mContext)) + private val shadeController: ShadeController = mock() + private val notificationAlertsInteractor: NotificationAlertsInteractor = mock() + private val keyguardStateController: KeyguardStateController = mock() + + private lateinit var underTest: StatusBarNotificationPresenter + + @Before + fun setup() { + mDependency.injectTestDependency(StatusBarStateController::class.java, mock()) + mDependency.injectTestDependency(ShadeController::class.java, shadeController) + mDependency.injectMockDependency(NotificationRemoteInputManager.Callback::class.java) + mDependency.injectMockDependency(NotificationShadeWindowController::class.java) + + whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(true) + + underTest = createPresenter() + if (VisualInterruptionRefactor.isEnabled) { + verifyAndCaptureSuppressors() + } else { + verifyAndCaptureLegacySuppressor() + } + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testInit_refactorDisabled() { + assertThat(VisualInterruptionRefactor.isEnabled).isFalse() + assertThat(alertsDisabledCondition).isNull() + assertThat(vrModeCondition).isNull() + assertThat(needsRedactionFilter).isNull() + assertThat(panelsDisabledCondition).isNull() + assertThat(interruptSuppressor).isNotNull() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testInit_refactorEnabled() { + assertThat(VisualInterruptionRefactor.isEnabled).isTrue() + assertThat(alertsDisabledCondition).isNotNull() + assertThat(vrModeCondition).isNotNull() + assertThat(needsRedactionFilter).isNotNull() + assertThat(panelsDisabledCondition).isNotNull() + assertThat(interruptSuppressor).isNull() + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testNoSuppressHeadsUp_default_refactorDisabled() { + assertThat(interruptSuppressor!!.suppressAwakeHeadsUp(createNotificationEntry())).isFalse() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testNoSuppressHeadsUp_default_refactorEnabled() { + assertThat(alertsDisabledCondition!!.shouldSuppress()).isFalse() + assertThat(vrModeCondition!!.shouldSuppress()).isFalse() + assertThat(needsRedactionFilter!!.shouldSuppress(createNotificationEntry())).isFalse() + assertThat(alertsDisabledCondition!!.shouldSuppress()).isFalse() + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressHeadsUp_disabledStatusBar_refactorDisabled() { + commandQueue.disable( + DEFAULT_DISPLAY, + StatusBarManager.DISABLE_EXPAND, + 0, + false, /* animate */ + ) + TestableLooper.get(this).processAllMessages() + + assertWithMessage("The panel should suppress heads up while disabled") + .that(interruptSuppressor!!.suppressAwakeHeadsUp(createNotificationEntry())) + .isTrue() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressHeadsUp_disabledStatusBar_refactorEnabled() { + commandQueue.disable( + DEFAULT_DISPLAY, + StatusBarManager.DISABLE_EXPAND, + 0, + false, /* animate */ + ) + TestableLooper.get(this).processAllMessages() + + assertWithMessage("The panel should suppress heads up while disabled") + .that(panelsDisabledCondition!!.shouldSuppress()) + .isTrue() + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressHeadsUp_disabledNotificationShade_refactorDisabled() { + commandQueue.disable( + DEFAULT_DISPLAY, + 0, + StatusBarManager.DISABLE2_NOTIFICATION_SHADE, + false, /* animate */ + ) + TestableLooper.get(this).processAllMessages() + + assertWithMessage( + "The panel should suppress interruptions while notification shade disabled" + ) + .that(interruptSuppressor!!.suppressAwakeHeadsUp(createNotificationEntry())) + .isTrue() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressHeadsUp_disabledNotificationShade_refactorEnabled() { + commandQueue.disable( + DEFAULT_DISPLAY, + 0, + StatusBarManager.DISABLE2_NOTIFICATION_SHADE, + false, /* animate */ + ) + TestableLooper.get(this).processAllMessages() + + assertWithMessage( + "The panel should suppress interruptions while notification shade disabled" + ) + .that(panelsDisabledCondition!!.shouldSuppress()) + .isTrue() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testPanelsDisabledConditionSuppressesPeek() { + val types: Set<VisualInterruptionType> = panelsDisabledCondition!!.types + assertThat(types).contains(VisualInterruptionType.PEEK) + assertThat(types) + .containsNoneOf(VisualInterruptionType.BUBBLE, VisualInterruptionType.PULSE) + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorDisabled() { + whenever(keyguardStateController.isShowing()).thenReturn(true) + whenever(keyguardStateController.isOccluded()).thenReturn(false) + + assertThat(interruptSuppressor!!.suppressAwakeHeadsUp(createFsiNotificationEntry())) + .isFalse() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testNoSuppressHeadsUp_FSI_nonOccludedKeyguard_refactorEnabled() { + whenever(keyguardStateController.isShowing()).thenReturn(true) + whenever(keyguardStateController.isOccluded()).thenReturn(false) + + assertThat(needsRedactionFilter!!.shouldSuppress(createFsiNotificationEntry())).isFalse() + + val types: Set<VisualInterruptionType> = needsRedactionFilter!!.types + assertThat(types).contains(VisualInterruptionType.PEEK) + assertThat(types) + .containsNoneOf(VisualInterruptionType.BUBBLE, VisualInterruptionType.PULSE) + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressInterruptions_vrMode_refactorDisabled() { + underTest.mVrMode = true + + assertWithMessage("Vr mode should suppress interruptions") + .that(interruptSuppressor!!.suppressAwakeInterruptions(createNotificationEntry())) + .isTrue() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressInterruptions_vrMode_refactorEnabled() { + underTest.mVrMode = true + + assertWithMessage("Vr mode should suppress interruptions") + .that(vrModeCondition!!.shouldSuppress()) + .isTrue() + + val types: Set<VisualInterruptionType> = vrModeCondition!!.types + assertThat(types).contains(VisualInterruptionType.PEEK) + assertThat(types).doesNotContain(VisualInterruptionType.PULSE) + assertThat(types).contains(VisualInterruptionType.BUBBLE) + } + + @Test + @DisableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressInterruptions_statusBarAlertsDisabled_refactorDisabled() { + whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false) + + assertWithMessage("When alerts aren't enabled, interruptions are suppressed") + .that(interruptSuppressor!!.suppressInterruptions(createNotificationEntry())) + .isTrue() + } + + @Test + @EnableFlags(VisualInterruptionRefactor.FLAG_NAME) + fun testSuppressInterruptions_statusBarAlertsDisabled_refactorEnabled() { + whenever(notificationAlertsInteractor.areNotificationAlertsEnabled()).thenReturn(false) + + assertWithMessage("When alerts aren't enabled, interruptions are suppressed") + .that(alertsDisabledCondition!!.shouldSuppress()) + .isTrue() + + val types: Set<VisualInterruptionType> = alertsDisabledCondition!!.types + assertThat(types).contains(VisualInterruptionType.PEEK) + assertThat(types).contains(VisualInterruptionType.PULSE) + assertThat(types).contains(VisualInterruptionType.BUBBLE) + } + + private fun createPresenter(): StatusBarNotificationPresenter { + val shadeViewController: ShadeViewController = mock() + + val notificationShadeWindowView: NotificationShadeWindowView = mock() + whenever(notificationShadeWindowView.resources).thenReturn(mContext.resources) + + val stackScrollLayoutController: NotificationStackScrollLayoutController = mock() + whenever(stackScrollLayoutController.view).thenReturn(mock()) + + val initController: InitController = InitController() + + return StatusBarNotificationPresenter( + mContext, + shadeViewController, + kosmos.panelExpansionInteractor, + /* quickSettingsController = */ mock(), + kosmos.headsUpManager, + notificationShadeWindowView, + kosmos.activityStarter, + stackScrollLayoutController, + kosmos.dozeScrimController, + kosmos.notificationShadeWindowController, + kosmos.dynamicPrivacyController, + keyguardStateController, + notificationAlertsInteractor, + kosmos.lockscreenShadeTransitionController, + kosmos.powerInteractor, + commandQueue, + kosmos.notificationLockscreenUserManager, + kosmos.sysuiStatusBarStateController, + /* notifShadeEventSource = */ mock(), + /* notificationMediaManager = */ mock(), + /* notificationGutsManager = */ mock(), + initController, + visualInterruptionDecisionProvider, + kosmos.notificationRemoteInputManager, + /* remoteInputManagerCallback = */ mock(), + /* notificationListContainer = */ mock(), + ) + .also { initController.executePostInitTasks() } + } + + private fun verifyAndCaptureSuppressors() { + interruptSuppressor = null + + val conditionCaptor = argumentCaptor<VisualInterruptionCondition>() + verify(visualInterruptionDecisionProvider, times(3)).addCondition(conditionCaptor.capture()) + val conditions: List<VisualInterruptionCondition> = conditionCaptor.allValues + alertsDisabledCondition = conditions[0] + vrModeCondition = conditions[1] + panelsDisabledCondition = conditions[2] + + val needsRedactionFilterCaptor = argumentCaptor<VisualInterruptionFilter>() + verify(visualInterruptionDecisionProvider).addFilter(needsRedactionFilterCaptor.capture()) + needsRedactionFilter = needsRedactionFilterCaptor.lastValue + } + + private fun verifyAndCaptureLegacySuppressor() { + alertsDisabledCondition = null + vrModeCondition = null + needsRedactionFilter = null + panelsDisabledCondition = null + + val suppressorCaptor = argumentCaptor<NotificationInterruptSuppressor>() + verify(visualInterruptionDecisionProvider).addLegacySuppressor(suppressorCaptor.capture()) + interruptSuppressor = suppressorCaptor.lastValue + } + + private fun createNotificationEntry(): NotificationEntry { + return NotificationEntryBuilder() + .setPkg("a") + .setOpPkg("a") + .setTag("a") + .setNotification(Builder(mContext, "a").build()) + .build() + } + + private fun createFsiNotificationEntry(): NotificationEntry { + val notification: Notification = + Builder(mContext, "a").setFullScreenIntent(mock(), true).build() + + return NotificationEntryBuilder() + .setPkg("a") + .setOpPkg("a") + .setTag("a") + .setNotification(notification) + .build() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 038722cd9608..bf1fbad074cd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -20,8 +20,6 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH -import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE import com.android.settingslib.mobile.MobileMappings import com.android.settingslib.mobile.TelephonyIcons.G import com.android.settingslib.mobile.TelephonyIcons.THREE_G @@ -40,12 +38,15 @@ import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesF import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState +import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository.Companion.DEFAULT_NETWORK_NAME import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel +import com.android.systemui.statusbar.pipeline.mobile.ui.model.MobileContentDescription import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot @@ -255,59 +256,146 @@ class MobileIconViewModelTest : SysuiTestCase() { @Test fun contentDescription_notInService_usesNoPhone() = testScope.runTest { - var latest: ContentDescription? = null - val job = underTest.contentDescription.onEach { latest = it }.launchIn(this) + val latest by collectLastValue(underTest.contentDescription) repository.isInService.value = false - assertThat((latest as ContentDescription.Resource).res) - .isEqualTo(PHONE_SIGNAL_STRENGTH_NONE) + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) + } - job.cancel() + @Test + fun contentDescription_includesNetworkName() = + testScope.runTest { + val latest by collectLastValue(underTest.contentDescription) + + repository.isInService.value = true + repository.networkName.value = NetworkNameModel.SubscriptionDerived("Test Network Name") + repository.numberOfLevels.value = 5 + repository.setAllLevels(3) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular("Test Network Name", THREE_BARS)) } @Test fun contentDescription_inService_usesLevel() = testScope.runTest { - var latest: ContentDescription? = null - val job = underTest.contentDescription.onEach { latest = it }.launchIn(this) + val latest by collectLastValue(underTest.contentDescription) repository.setAllLevels(2) - assertThat((latest as ContentDescription.Resource).res) - .isEqualTo(PHONE_SIGNAL_STRENGTH[2]) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS)) repository.setAllLevels(0) - assertThat((latest as ContentDescription.Resource).res) - .isEqualTo(PHONE_SIGNAL_STRENGTH[0]) - job.cancel() + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) } @Test - fun contentDescription_nonInflated_invalidLevelIsNull() = + fun contentDescription_nonInflated_invalidLevelUsesNoSignalText() = testScope.runTest { val latest by collectLastValue(underTest.contentDescription) repository.inflateSignalStrength.value = false repository.setAllLevels(-1) - assertThat(latest).isNull() + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) repository.setAllLevels(100) - assertThat(latest).isNull() + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) + } + + @Test + fun contentDescription_nonInflated_levelStrings() = + testScope.runTest { + val latest by collectLastValue(underTest.contentDescription) + + repository.inflateSignalStrength.value = false + repository.setAllLevels(0) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) + + repository.setAllLevels(1) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, ONE_BAR)) + + repository.setAllLevels(2) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS)) + + repository.setAllLevels(3) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, THREE_BARS)) + + repository.setAllLevels(4) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FULL_BARS)) } @Test - fun contentDescription_inflated_invalidLevelIsNull() = + fun contentDescription_inflated_invalidLevelUsesNoSignalText() = testScope.runTest { val latest by collectLastValue(underTest.contentDescription) repository.inflateSignalStrength.value = true repository.numberOfLevels.value = 6 + repository.setAllLevels(-2) - assertThat(latest).isNull() + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) repository.setAllLevels(100) - assertThat(latest).isNull() + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, NO_SIGNAL)) + } + + @Test + fun contentDescription_inflated_levelStrings() = + testScope.runTest { + val latest by collectLastValue(underTest.contentDescription) + + repository.inflateSignalStrength.value = true + repository.numberOfLevels.value = 6 + + // Note that the _repo_ level is 1 lower than the reported level through the interactor + + repository.setAllLevels(0) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, ONE_BAR)) + + repository.setAllLevels(1) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, TWO_BARS)) + + repository.setAllLevels(2) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, THREE_BARS)) + + repository.setAllLevels(3) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FOUR_BARS)) + + repository.setAllLevels(4) + + assertThat(latest as MobileContentDescription.Cellular) + .isEqualTo(MobileContentDescription.Cellular(DEFAULT_NETWORK_NAME, FULL_BARS)) } @Test @@ -323,7 +411,10 @@ class MobileIconViewModelTest : SysuiTestCase() { repository.setAllLevels(i) when (i) { -1, - 5 -> assertWithMessage("Level $i is expected to be null").that(latest).isNull() + 5 -> + assertWithMessage("Level $i is expected to be 'no signal'") + .that((latest as MobileContentDescription.Cellular).levelDescriptionRes) + .isEqualTo(NO_SIGNAL) else -> assertWithMessage("Level $i is expected not to be null") .that(latest) @@ -344,7 +435,10 @@ class MobileIconViewModelTest : SysuiTestCase() { repository.setAllLevels(i) when (i) { -2, - 5 -> assertWithMessage("Level $i is expected to be null").that(latest).isNull() + 5 -> + assertWithMessage("Level $i is expected to be 'no signal'") + .that((latest as MobileContentDescription.Cellular).levelDescriptionRes) + .isEqualTo(NO_SIGNAL) else -> assertWithMessage("Level $i is not expected to be null") .that(latest) @@ -967,5 +1061,13 @@ class MobileIconViewModelTest : SysuiTestCase() { companion object { private const val SUB_1_ID = 1 + + // For convenience, just define these as constants + private val NO_SIGNAL = R.string.accessibility_no_signal + private val ONE_BAR = R.string.accessibility_one_bar + private val TWO_BARS = R.string.accessibility_two_bars + private val THREE_BARS = R.string.accessibility_three_bars + private val FOUR_BARS = R.string.accessibility_four_bars + private val FULL_BARS = R.string.accessibility_signal_full } } 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/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewBinder.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewBinder.kt index 9888574071e6..a2ca12c13a3e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewBinder.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewBinder.kt @@ -30,6 +30,7 @@ class FakeHomeStatusBarViewBinder : HomeStatusBarViewBinder { var listener: StatusBarVisibilityChangeListener? = null override fun bind( + displayId: Int, view: View, viewModel: HomeStatusBarViewModel, systemEventChipAnimateIn: ((View) -> Unit)?, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt index 3dcb82811408..72527ddf65b1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/view/ViewUtilTest.kt @@ -105,6 +105,20 @@ class ViewUtilTest : SysuiTestCase() { assertThat(outRect.top).isEqualTo(VIEW_TOP) assertThat(outRect.bottom).isEqualTo(VIEW_BOTTOM) } + + @Test + fun viewBoundsOnScreen_viewAnchoredAtOriginInWindow() { + // view is anchored at 0,0 in its window + view.setLeftTopRightBottom(0, 0, VIEW_RIGHT - VIEW_LEFT, VIEW_BOTTOM - VIEW_TOP) + + val outRect = Rect() + view.viewBoundsOnScreen(outRect) + + assertThat(outRect.left).isEqualTo(VIEW_LEFT) + assertThat(outRect.right).isEqualTo(VIEW_RIGHT) + assertThat(outRect.top).isEqualTo(VIEW_TOP) + assertThat(outRect.bottom).isEqualTo(VIEW_BOTTOM) + } } private const val VIEW_LEFT = 30 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/color/numpad_key_color_secondary.xml b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml index 47641ee64ee1..4a14f3baaafc 100644 --- a/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml +++ b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorSecondaryFixedDim"/> + <item android:color="@androidprv:color/materialColorSecondaryFixedDim"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml index 5e7cf3ee41fb..6a885a733dba 100644 --- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml +++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml @@ -19,7 +19,7 @@ android:color="?attr/wallpaperTextColorSecondary"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorTertiaryFixed"/> + <solid android:color="@androidprv:color/materialColorTertiaryFixed"/> <corners android:radius="24dp"/> </shape> </item> diff --git a/packages/SystemUI/res-keyguard/drawable/progress_bar.xml b/packages/SystemUI/res-keyguard/drawable/progress_bar.xml index 910a74ad5faf..455d9d3c00fa 100644 --- a/packages/SystemUI/res-keyguard/drawable/progress_bar.xml +++ b/packages/SystemUI/res-keyguard/drawable/progress_bar.xml @@ -26,7 +26,7 @@ android:layout_height="match_parent" android:shape="rectangle"> <corners android:radius="30dp" /> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHighest" /> </shape> </item> <item diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml index 83736e9d9473..eb9ee03a2cd4 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml @@ -27,8 +27,8 @@ android:background="@drawable/kg_bouncer_secondary_button" android:drawablePadding="10dp" android:drawableStart="@drawable/ic_no_sim" - android:drawableTint="?androidprv:attr/materialColorOnSurface" + android:drawableTint="@androidprv:color/materialColorOnSurface" android:text="@string/disable_carrier_button_text" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="@dimen/kg_status_line_font_size" android:visibility="gone" /> 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-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index da12dd731c23..b256518e99ac 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -23,13 +23,13 @@ <style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView"> <item name="android:textSize">@dimen/kg_status_line_font_size</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="Keyguard.Bouncer.PrimaryMessage" parent="Theme.SystemUI"> <item name="android:textSize">18sp</item> <item name="android:lineHeight">24dp</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:singleLine">true</item> <item name="android:textAlignment">center</item> <item name="android:ellipsize">marquee</item> @@ -41,10 +41,10 @@ <item name="android:textAlignment">center</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:ellipsize">end</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> </style> <style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI"> - <item name="android:textColor">?androidprv:attr/materialColorOnTertiaryFixed</item> + <item name="android:textColor">@androidprv:color/materialColorOnTertiaryFixed</item> <item name="android:textSize">16sp</item> <item name="android:background">@drawable/kg_emergency_button_background</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> diff --git a/packages/SystemUI/res/color/connected_network_primary_color.xml b/packages/SystemUI/res/color/connected_network_primary_color.xml index f173c8dd5473..920047a705e8 100644 --- a/packages/SystemUI/res/color/connected_network_primary_color.xml +++ b/packages/SystemUI/res/color/connected_network_primary_color.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorOnPrimaryContainer" /> + <item android:color="@androidprv:color/materialColorOnPrimaryContainer" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/disconnected_network_primary_color.xml b/packages/SystemUI/res/color/disconnected_network_primary_color.xml index 536bf78b7b60..f4b19a71fefd 100644 --- a/packages/SystemUI/res/color/disconnected_network_primary_color.xml +++ b/packages/SystemUI/res/color/disconnected_network_primary_color.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorPrimaryContainer" /> + <item android:color="@androidprv:color/materialColorPrimaryContainer" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/menu_item_text.xml b/packages/SystemUI/res/color/menu_item_text.xml index 0d05650b8082..c1c9e2c1938e 100644 --- a/packages/SystemUI/res/color/menu_item_text.xml +++ b/packages/SystemUI/res/color/menu_item_text.xml @@ -17,8 +17,8 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorOnSurface" + android:color="@androidprv:color/materialColorOnSurface" android:alpha="0.38" /> - <item android:color="?androidprv:attr/materialColorOnSurface"/> + <item android:color="@androidprv:color/materialColorOnSurface"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/notification_focus_overlay_color.xml b/packages/SystemUI/res/color/notification_focus_overlay_color.xml index 6a3c7a148963..55843635dee7 100644 --- a/packages/SystemUI/res/color/notification_focus_overlay_color.xml +++ b/packages/SystemUI/res/color/notification_focus_overlay_color.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:state_focused="true" android:color="?androidprv:attr/materialColorSecondary" /> + <item android:state_focused="true" android:color="@androidprv:color/materialColorSecondary" /> <item android:color="@color/transparent" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml index d1b8a064724d..e0873b887d8d 100644 --- a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml +++ b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_selected="true" - android:color="?androidprv:attr/materialColorOnSurfaceVariant" /> + android:color="@androidprv:color/materialColorOnSurfaceVariant" /> <item android:color="@color/notification_guts_priority_button_bg_stroke_color" /> </selector> diff --git a/packages/SystemUI/res/color/notification_guts_priority_contents.xml b/packages/SystemUI/res/color/notification_guts_priority_contents.xml index cc8c25a2d1ec..3b221e76a91d 100644 --- a/packages/SystemUI/res/color/notification_guts_priority_contents.xml +++ b/packages/SystemUI/res/color/notification_guts_priority_contents.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_selected="true" - android:color="?androidprv:attr/materialColorOnSurfaceVariant" /> + android:color="@androidprv:color/materialColorOnSurfaceVariant" /> <item android:color="@color/notification_guts_priority_button_content_color" /> </selector> diff --git a/packages/SystemUI/res/color/notification_state_color_default.xml b/packages/SystemUI/res/color/notification_state_color_default.xml index a14a7ad9d2da..9d77f604c166 100644 --- a/packages/SystemUI/res/color/notification_state_color_default.xml +++ b/packages/SystemUI/res/color/notification_state_color_default.xml @@ -19,7 +19,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <!-- Pressed state's alpha is set to 0.00 temporarily until this bug is resolved permanently b/313920497 Design intended alpha is 0.15--> - <item android:state_pressed="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.00" /> - <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha="0.11" /> + <item android:state_pressed="true" android:color="@androidprv:color/materialColorOnSurface" android:alpha="0.00" /> + <item android:state_hovered="true" android:color="@androidprv:color/materialColorOnSurface" android:alpha="0.11" /> <item android:color="@color/transparent" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_filled_background.xml b/packages/SystemUI/res/color/qs_dialog_btn_filled_background.xml index 40bab5ed08f2..898d5891b7e2 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_filled_background.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_filled_background.xml @@ -17,7 +17,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorPrimary" + android:color="@androidprv:color/materialColorPrimary" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorPrimary"/> + <item android:color="@androidprv:color/materialColorPrimary"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_filled_large_background.xml b/packages/SystemUI/res/color/qs_dialog_btn_filled_large_background.xml index f8d4af57229b..c8ab4ad88ca1 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_filled_large_background.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_filled_large_background.xml @@ -16,7 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorPrimaryFixed" + android:color="@androidprv:color/materialColorPrimaryFixed" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorPrimaryFixed"/> + <item android:color="@androidprv:color/materialColorPrimaryFixed"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_filled_large_text.xml b/packages/SystemUI/res/color/qs_dialog_btn_filled_large_text.xml index faba8fc4c755..60b6245ca301 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_filled_large_text.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_filled_large_text.xml @@ -16,7 +16,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorOnPrimaryFixed" + android:color="@androidprv:color/materialColorOnPrimaryFixed" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorOnPrimaryFixed"/> + <item android:color="@androidprv:color/materialColorOnPrimaryFixed"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_filled_text_color.xml b/packages/SystemUI/res/color/qs_dialog_btn_filled_text_color.xml index e76ad991a92c..a5497a54ec66 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_filled_text_color.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_filled_text_color.xml @@ -17,7 +17,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorOnPrimary" + android:color="@androidprv:color/materialColorOnPrimary" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorOnPrimary"/> + <item android:color="@androidprv:color/materialColorOnPrimary"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_outline.xml b/packages/SystemUI/res/color/qs_dialog_btn_outline.xml index 1adfe5b19d70..7ef7e062e579 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_outline.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_outline.xml @@ -17,7 +17,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorPrimary" + android:color="@androidprv:color/materialColorPrimary" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorPrimary"/> + <item android:color="@androidprv:color/materialColorPrimary"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/qs_dialog_btn_outline_text.xml b/packages/SystemUI/res/color/qs_dialog_btn_outline_text.xml index 5dc994f23f2b..f139008640ad 100644 --- a/packages/SystemUI/res/color/qs_dialog_btn_outline_text.xml +++ b/packages/SystemUI/res/color/qs_dialog_btn_outline_text.xml @@ -17,7 +17,7 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_enabled="false" - android:color="?androidprv:attr/materialColorOnSurface" + android:color="@androidprv:color/materialColorOnSurface" android:alpha="0.30"/> - <item android:color="?androidprv:attr/materialColorOnSurface"/> + <item android:color="@androidprv:color/materialColorOnSurface"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/remote_input_hint.xml b/packages/SystemUI/res/color/remote_input_hint.xml index 0d90ee6b47c6..75d2bb8f2dfe 100644 --- a/packages/SystemUI/res/color/remote_input_hint.xml +++ b/packages/SystemUI/res/color/remote_input_hint.xml @@ -16,5 +16,5 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" /> + <item android:color="@androidprv:color/materialColorOnSurfaceVariant" android:alpha=".6" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/remote_input_send.xml b/packages/SystemUI/res/color/remote_input_send.xml index 0acc66b9050f..4c61c0c69ca1 100644 --- a/packages/SystemUI/res/color/remote_input_send.xml +++ b/packages/SystemUI/res/color/remote_input_send.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:state_enabled="false" android:color="?androidprv:attr/materialColorPrimary" android:alpha=".3" /> - <item android:color="?androidprv:attr/materialColorPrimary" /> + <item android:state_enabled="false" android:color="@androidprv:color/materialColorPrimary" android:alpha=".3" /> + <item android:color="@androidprv:color/materialColorPrimary" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/remote_input_text.xml b/packages/SystemUI/res/color/remote_input_text.xml index bf2c198fe540..2ec09cde26ca 100644 --- a/packages/SystemUI/res/color/remote_input_text.xml +++ b/packages/SystemUI/res/color/remote_input_text.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:state_enabled="false" android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" /> - <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" /> + <item android:state_enabled="false" android:color="@androidprv:color/materialColorOnSurfaceVariant" android:alpha=".6" /> + <item android:color="@androidprv:color/materialColorOnSurfaceVariant" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/screenshare_options_spinner_background.xml b/packages/SystemUI/res/color/screenshare_options_spinner_background.xml index 922813dcbe64..f3059f6e4627 100644 --- a/packages/SystemUI/res/color/screenshare_options_spinner_background.xml +++ b/packages/SystemUI/res/color/screenshare_options_spinner_background.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item android:state_hovered="false" android:state_focused="false" android:color="@android:color/transparent" /> - <item android:state_focused="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha=".1" /> - <item android:state_hovered="true" android:color="?androidprv:attr/materialColorOnSurface" android:alpha=".08" /> + <item android:state_focused="true" android:color="@androidprv:color/materialColorOnSurface" android:alpha=".1" /> + <item android:state_hovered="true" android:color="@androidprv:color/materialColorOnSurface" android:alpha=".08" /> </selector> diff --git a/packages/SystemUI/res/color/slider_active_track_color.xml b/packages/SystemUI/res/color/slider_active_track_color.xml index a5aa58dd6b51..8ba5e4901a7a 100644 --- a/packages/SystemUI/res/color/slider_active_track_color.xml +++ b/packages/SystemUI/res/color/slider_active_track_color.xml @@ -14,6 +14,6 @@ ~ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorPrimary" android:state_enabled="true" /> - <item android:color="?androidprv:attr/materialColorSurfaceContainerHighest" /> + <item android:color="@androidprv:color/materialColorPrimary" android:state_enabled="true" /> + <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/slider_inactive_track_color.xml b/packages/SystemUI/res/color/slider_inactive_track_color.xml index 89aef776c00e..7980f804a516 100644 --- a/packages/SystemUI/res/color/slider_inactive_track_color.xml +++ b/packages/SystemUI/res/color/slider_inactive_track_color.xml @@ -14,6 +14,6 @@ ~ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorSurfaceContainerHighest" android:state_enabled="true" /> - <item android:color="?androidprv:attr/materialColorPrimary" /> + <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" android:state_enabled="true" /> + <item android:color="@androidprv:color/materialColorPrimary" /> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/slider_thumb_color.xml b/packages/SystemUI/res/color/slider_thumb_color.xml index 5206049edd41..8a98902426f8 100644 --- a/packages/SystemUI/res/color/slider_thumb_color.xml +++ b/packages/SystemUI/res/color/slider_thumb_color.xml @@ -15,6 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/materialColorSurfaceContainerHighest" android:state_enabled="false" /> - <item android:color="?androidprv:attr/materialColorPrimary" /> + <item android:color="@androidprv:color/materialColorSurfaceContainerHighest" android:state_enabled="false" /> + <item android:color="@androidprv:color/materialColorPrimary" /> </selector> diff --git a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml index 16076b17a6e5..d54164be4632 100644 --- a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml +++ b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_down.xml @@ -24,8 +24,8 @@ android:viewportHeight="24"> <path android:pathData="M0,12C0,5.373 5.373,0 12,0C18.627,0 24,5.373 24,12C24,18.627 18.627,24 12,24C5.373,24 0,18.627 0,12Z" - android:fillColor="?androidprv:attr/materialColorSurfaceContainerHigh"/> + android:fillColor="@androidprv:color/materialColorSurfaceContainerHigh"/> <path android:pathData="M7.607,9.059L6.667,9.999L12,15.332L17.333,9.999L16.393,9.059L12,13.445" - android:fillColor="?androidprv:attr/materialColorOnSurface"/> + android:fillColor="@androidprv:color/materialColorOnSurface"/> </vector> diff --git a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml index 309770ddd76d..81184a111d25 100644 --- a/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml +++ b/packages/SystemUI/res/drawable-night/privacy_dialog_expand_toggle_up.xml @@ -24,8 +24,8 @@ android:viewportHeight="24"> <path android:pathData="M0,12C0,5.3726 5.3726,0 12,0C18.6274,0 24,5.3726 24,12C24,18.6274 18.6274,24 12,24C5.3726,24 0,18.6274 0,12Z" - android:fillColor="?androidprv:attr/materialColorSurfaceContainerHigh"/> + android:fillColor="@androidprv:color/materialColorSurfaceContainerHigh"/> <path android:pathData="M16.3934,14.9393L17.3334,13.9993L12.0001,8.666L6.6667,13.9993L7.6068,14.9393L12.0001,10.5527" - android:fillColor="?androidprv:attr/materialColorOnSurface"/> + android:fillColor="@androidprv:color/materialColorOnSurface"/> </vector> diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml index 9492472a2be1..0958c840994d 100644 --- a/packages/SystemUI/res/drawable/action_chip_background.xml +++ b/packages/SystemUI/res/drawable/action_chip_background.xml @@ -20,7 +20,7 @@ android:color="@color/overlay_button_ripple"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSecondary"/> + <solid android:color="@androidprv:color/materialColorSecondary"/> <corners android:radius="@dimen/overlay_button_corner_radius"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml index 2ee27107d900..5aced9d424fa 100644 --- a/packages/SystemUI/res/drawable/action_chip_container_background.xml +++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml @@ -18,6 +18,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> + <solid android:color="@androidprv:color/materialColorSurfaceBright"/> <corners android:radius="@dimen/overlay_action_container_corner_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml b/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml index fdafe6d8e335..63d026842234 100644 --- a/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml +++ b/packages/SystemUI/res/drawable/biometric_prompt_vertical_list_content_view_background.xml @@ -18,6 +18,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh"/> <corners android:radius="@dimen/biometric_prompt_content_corner_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/brightness_bar.xml b/packages/SystemUI/res/drawable/brightness_bar.xml index 3d1c1fbd6ce7..a32496b25041 100644 --- a/packages/SystemUI/res/drawable/brightness_bar.xml +++ b/packages/SystemUI/res/drawable/brightness_bar.xml @@ -21,7 +21,7 @@ android:viewportHeight="48"> <path android:pathData="M2,22L302,22A2,2 0,0 1,304 24L304,24A2,2 0,0 1,302 26L2,26A2,2 0,0 1,0 24L0,24A2,2 0,0 1,2 22z" - android:fillColor="?androidprv:attr/customColorShadeInactive"/> + android:fillColor="@androidprv:color/customColorShadeInactive"/> <path android:pathData="M24,0L205.71,0A24,24 0,0 1,229.71 24L229.71,24A24,24 0,0 1,205.71 48L24,48A24,24 0,0 1,0 24L0,24A24,24 0,0 1,24 0z" android:fillColor="?attr/shadeActive"/> diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml index ec15b10851c5..88d3ecb3f423 100644 --- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml +++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml @@ -25,7 +25,7 @@ <shape> <size android:height="@dimen/rounded_slider_track_width" /> <corners android:radius="@dimen/rounded_slider_track_corner_radius" /> - <solid android:color="?androidprv:attr/customColorShadeInactive" /> + <solid android:color="@androidprv:color/customColorShadeInactive" /> </shape> </inset> </item> diff --git a/packages/SystemUI/res/drawable/brightness_slider_focus_bg.xml b/packages/SystemUI/res/drawable/brightness_slider_focus_bg.xml index 22406ec52d00..546289837e8f 100644 --- a/packages/SystemUI/res/drawable/brightness_slider_focus_bg.xml +++ b/packages/SystemUI/res/drawable/brightness_slider_focus_bg.xml @@ -22,7 +22,7 @@ <inset android:inset="-5dp"> <shape> <corners android:radius="16dp"/> - <stroke android:width="3dp" android:color="?androidprv:attr/materialColorSecondaryFixed"/> + <stroke android:width="3dp" android:color="@androidprv:color/materialColorSecondaryFixed"/> </shape> </inset> </item> diff --git a/packages/SystemUI/res/drawable/chipbar_background.xml b/packages/SystemUI/res/drawable/chipbar_background.xml index 7530f5ba244a..15c9fcb1370a 100644 --- a/packages/SystemUI/res/drawable/chipbar_background.xml +++ b/packages/SystemUI/res/drawable/chipbar_background.xml @@ -17,6 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/materialColorSecondaryFixed" /> + <solid android:color="@androidprv:color/materialColorSecondaryFixed" /> <corners android:radius="32dp" /> </shape> diff --git a/packages/SystemUI/res/drawable/chipbar_end_button_background.xml b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml index a3832eef957f..fcf5b30f6211 100644 --- a/packages/SystemUI/res/drawable/chipbar_end_button_background.xml +++ b/packages/SystemUI/res/drawable/chipbar_end_button_background.xml @@ -20,7 +20,7 @@ android:color="?android:textColorPrimary"> <item android:id="@android:id/background"> <shape> - <solid android:color="?androidprv:attr/materialColorPrimaryFixedDim"/> + <solid android:color="@androidprv:color/materialColorPrimaryFixedDim"/> <corners android:radius="24dp" /> </shape> </item> diff --git a/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml index d7000d7f5a5c..b8911637f300 100644 --- a/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml +++ b/packages/SystemUI/res/drawable/contextual_edu_dialog_bg.xml @@ -19,6 +19,6 @@ android:insetBottom="@dimen/contextual_edu_dialog_elevation"> <shape> <corners android:radius="28dp" /> - <solid android:color="?androidprv:attr/materialColorTertiaryFixed" /> + <solid android:color="@androidprv:color/materialColorTertiaryFixed" /> </shape> </inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml index f35975ee8548..5ddc860f85a2 100644 --- a/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml +++ b/packages/SystemUI/res/drawable/hearing_devices_spinner_popup_background.xml @@ -18,5 +18,5 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> <corners android:radius="@dimen/hearing_devices_preset_spinner_background_radius"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_check_circle_filled_24dp.xml b/packages/SystemUI/res/drawable/ic_check_circle_filled_24dp.xml index 16e2a3db2e95..307f7eb8f17e 100644 --- a/packages/SystemUI/res/drawable/ic_check_circle_filled_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_check_circle_filled_24dp.xml @@ -18,7 +18,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:width="24dp" android:height="24dp" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:viewportHeight="24" android:viewportWidth="24"> <path diff --git a/packages/SystemUI/res/drawable/ic_circle_outline_24dp.xml b/packages/SystemUI/res/drawable/ic_circle_outline_24dp.xml index 82fa4f08d0c8..8304fd5be16e 100644 --- a/packages/SystemUI/res/drawable/ic_circle_outline_24dp.xml +++ b/packages/SystemUI/res/drawable/ic_circle_outline_24dp.xml @@ -18,7 +18,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:width="24dp" android:height="24dp" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:viewportHeight="24" android:viewportWidth="24"> <path 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/drawable/ic_shortcutlist_search.xml b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml index 0406f0e4304e..ddff88484796 100644 --- a/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml +++ b/packages/SystemUI/res/drawable/ic_shortcutlist_search.xml @@ -19,7 +19,7 @@ android:height="24dp" android:viewportWidth="48" android:viewportHeight="48" - android:tint="?androidprv:attr/materialColorOnSurfaceVariant"> + android:tint="@androidprv:color/materialColorOnSurfaceVariant"> <path android:fillColor="@android:color/white" android:strokeColor="@android:color/white" diff --git a/packages/SystemUI/res/drawable/immersive_cling_bg.xml b/packages/SystemUI/res/drawable/immersive_cling_bg.xml index de29c32390e1..b28a423ea06b 100644 --- a/packages/SystemUI/res/drawable/immersive_cling_bg.xml +++ b/packages/SystemUI/res/drawable/immersive_cling_bg.xml @@ -20,5 +20,5 @@ <corners android:bottomLeftRadius="28dp" android:bottomRightRadius="28dp"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape> diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml index 32dc4b335f7e..6ad46d837acd 100644 --- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml +++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml @@ -20,7 +20,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh"/> <size android:width="@dimen/keyguard_affordance_fixed_width" android:height="@dimen/keyguard_affordance_fixed_height"/> diff --git a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml index fe76ba7e5b8c..fab0cc204e87 100644 --- a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml +++ b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml @@ -26,7 +26,7 @@ </item> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSecondaryFixed" /> + <solid android:color="@androidprv:color/materialColorSecondaryFixed" /> <corners android:radius="@dimen/keyguard_affordance_fixed_radius" /> </shape> </item> diff --git a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml index b9597375c3df..1d5e09d9b260 100644 --- a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml +++ b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml @@ -26,7 +26,7 @@ <padding android:left="20dp" android:right="20dp" /> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> </shape> </inset> </item> diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml index 84e2231738d4..200976b1fb31 100644 --- a/packages/SystemUI/res/drawable/notification_guts_bg.xml +++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml @@ -17,7 +17,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> <!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners --> <corners android:radius="1dp" /> </shape> diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml index 715be074eaa8..db3b969cca39 100644 --- a/packages/SystemUI/res/drawable/notification_material_bg.xml +++ b/packages/SystemUI/res/drawable/notification_material_bg.xml @@ -20,7 +20,7 @@ android:color="?android:attr/colorControlHighlight"> <item> <shape> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHigh" /> </shape> </item> <item> diff --git a/packages/SystemUI/res/drawable/overlay_border.xml b/packages/SystemUI/res/drawable/overlay_border.xml index a59f9239dfca..381849be5730 100644 --- a/packages/SystemUI/res/drawable/overlay_border.xml +++ b/packages/SystemUI/res/drawable/overlay_border.xml @@ -18,6 +18,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> + <solid android:color="@androidprv:color/materialColorSurfaceBright"/> <corners android:radius="16dp"/> </shape> diff --git a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml index f8b99f4a0ee4..299b4c9ab1d0 100644 --- a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml +++ b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_down.xml @@ -23,8 +23,8 @@ android:viewportHeight="24"> <path android:pathData="M0,12C0,5.373 5.373,0 12,0C18.627,0 24,5.373 24,12C24,18.627 18.627,24 12,24C5.373,24 0,18.627 0,12Z" - android:fillColor="?androidprv:attr/materialColorSurfaceContainerHigh"/> + android:fillColor="@androidprv:color/materialColorSurfaceContainerHigh"/> <path android:pathData="M7.607,9.059L6.667,9.999L12,15.332L17.333,9.999L16.393,9.059L12,13.445" - android:fillColor="?androidprv:attr/materialColorOnSurface"/> + android:fillColor="@androidprv:color/materialColorOnSurface"/> </vector> diff --git a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml index ae60d517ceb4..68e73e941e00 100644 --- a/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml +++ b/packages/SystemUI/res/drawable/privacy_dialog_expand_toggle_up.xml @@ -23,8 +23,8 @@ android:viewportHeight="24"> <path android:pathData="M0,12C0,5.3726 5.3726,0 12,0C18.6274,0 24,5.3726 24,12C24,18.6274 18.6274,24 12,24C5.3726,24 0,18.6274 0,12Z" - android:fillColor="?androidprv:attr/materialColorSurfaceContainerHigh"/> + android:fillColor="@androidprv:color/materialColorSurfaceContainerHigh"/> <path android:pathData="M16.3934,14.9393L17.3334,13.9993L12.0001,8.666L6.6667,13.9993L7.6068,14.9393L12.0001,10.5527" - android:fillColor="?androidprv:attr/materialColorOnSurface"/> + android:fillColor="@androidprv:color/materialColorOnSurface"/> </vector> diff --git a/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml b/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml index 3c1668405909..e90473bf54f3 100644 --- a/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml +++ b/packages/SystemUI/res/drawable/qs_hearing_devices_related_tools_background.xml @@ -21,7 +21,7 @@ android:color="?android:attr/colorControlHighlight"> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimaryContainer"/> + <solid android:color="@androidprv:color/materialColorPrimaryContainer"/> <corners android:radius="@dimen/hearing_devices_preset_spinner_background_radius"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml index 33f0d02efb2a..cdf6a1a00316 100644 --- a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml +++ b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml @@ -21,6 +21,6 @@ <corners android:radius="30dp" /> <stroke android:width="3dp" - android:color="?androidprv:attr/materialColorSecondaryFixed" /> + android:color="@androidprv:color/materialColorSecondaryFixed" /> </shape> </inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml index 45d1a530cd20..01ecbcf9956b 100644 --- a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml +++ b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml @@ -17,10 +17,10 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceDim" /> + <solid android:color="@androidprv:color/materialColorSurfaceDim" /> <stroke android:width="@dimen/remote_input_view_text_stroke" - android:color="?androidprv:attr/materialColorPrimary"/> + android:color="@androidprv:color/materialColorPrimary"/> <padding android:bottom="0dp" android:left="12dp" diff --git a/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml b/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml index 321a04a1fb5e..323cb77eb37f 100644 --- a/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml +++ b/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml @@ -17,5 +17,5 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> <corners android:radius="@dimen/screenrecord_spinner_background_radius"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainer" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainer" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/screenshot_edit_background.xml b/packages/SystemUI/res/drawable/screenshot_edit_background.xml index 07e5aff3954d..ef1c30f10605 100644 --- a/packages/SystemUI/res/drawable/screenshot_edit_background.xml +++ b/packages/SystemUI/res/drawable/screenshot_edit_background.xml @@ -20,7 +20,7 @@ android:color="@color/overlay_button_ripple"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSecondaryFixedDim"/> + <solid android:color="@androidprv:color/materialColorSecondaryFixedDim"/> <corners android:radius="16dp"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml index fab2d8db859f..2063d9fa55e0 100644 --- a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml @@ -20,7 +20,7 @@ android:color="?android:attr/colorControlHighlight"> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorPrimaryContainer"/> + <solid android:color="@androidprv:color/materialColorPrimaryContainer"/> <corners android:radius="@dimen/settingslib_switch_bar_radius"/> </shape> </item> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml index e316a93c1c3d..70a1e84e7e40 100644 --- a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml +++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml @@ -24,7 +24,7 @@ <size android:height="@dimen/settingslib_switch_thumb_size" android:width="@dimen/settingslib_switch_thumb_size"/> - <solid android:color="?androidprv:attr/materialColorOnPrimary"/> + <solid android:color="@androidprv:color/materialColorOnPrimary"/> </shape> </item> </layer-list> diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml index e2e64684f9c3..e3476a42b2bc 100644 --- a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml +++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml @@ -22,6 +22,6 @@ android:height="@dimen/settingslib_switch_track_height"> <padding android:left="@dimen/settingslib_switch_thumb_margin" android:right="@dimen/settingslib_switch_thumb_margin"/> - <solid android:color="?androidprv:attr/materialColorPrimary"/> + <solid android:color="@androidprv:color/materialColorPrimary"/> <corners android:radius="@dimen/settingslib_switch_track_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_background.xml b/packages/SystemUI/res/drawable/shelf_action_chip_background.xml index 63600beff126..faa3d6869a34 100644 --- a/packages/SystemUI/res/drawable/shelf_action_chip_background.xml +++ b/packages/SystemUI/res/drawable/shelf_action_chip_background.xml @@ -20,7 +20,7 @@ android:color="@color/overlay_button_ripple"> <item android:id="@android:id/background"> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSecondary"/> + <solid android:color="@androidprv:color/materialColorSecondary"/> <corners android:radius="10000dp"/> <!-- fully-rounded radius --> </shape> </item> diff --git a/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml index ad6c154692ec..82f034bb1cdd 100644 --- a/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml +++ b/packages/SystemUI/res/drawable/shelf_action_chip_container_background.xml @@ -21,7 +21,7 @@ <shape xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> + <solid android:color="@androidprv:color/materialColorSurfaceBright"/> <corners android:radius="10000dp"/> <!-- fully-rounded radius --> </shape> </inset>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/shortcut_button_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_colored.xml index 2e2d9b9a3e35..b6a14c8188ab 100644 --- a/packages/SystemUI/res/drawable/shortcut_button_colored.xml +++ b/packages/SystemUI/res/drawable/shortcut_button_colored.xml @@ -22,7 +22,7 @@ <item> <shape android:shape="rectangle"> <corners android:radius="@dimen/ksh_button_corner_radius"/> - <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> + <solid android:color="@androidprv:color/materialColorSurfaceBright"/> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml index 5b88bb922a9e..2b95a9462365 100644 --- a/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml +++ b/packages/SystemUI/res/drawable/shortcut_button_focus_colored.xml @@ -22,7 +22,7 @@ <item> <shape android:shape="rectangle"> <corners android:radius="@dimen/ksh_button_corner_radius"/> - <solid android:color="?androidprv:attr/materialColorPrimary"/> + <solid android:color="@androidprv:color/materialColorPrimary"/> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/drawable/shortcut_search_background.xml b/packages/SystemUI/res/drawable/shortcut_search_background.xml index d6847f0abb8d..07e5b3dec059 100644 --- a/packages/SystemUI/res/drawable/shortcut_search_background.xml +++ b/packages/SystemUI/res/drawable/shortcut_search_background.xml @@ -19,7 +19,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item> <shape android:shape="rectangle"> - <solid android:color="?androidprv:attr/materialColorSurfaceBright" /> + <solid android:color="@androidprv:color/materialColorSurfaceBright" /> <corners android:radius="@dimen/ksh_search_box_corner_radius" /> </shape> </item> diff --git a/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml b/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml index 2675906580f1..6390c11dae36 100644 --- a/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml +++ b/packages/SystemUI/res/drawable/shortcut_search_cancel_button.xml @@ -20,7 +20,7 @@ <shape android:shape="oval"> <size android:width="24dp" android:height="24dp" /> - <solid android:color="?androidprv:attr/materialColorSurfaceBright"/> + <solid android:color="@androidprv:color/materialColorSurfaceBright"/> </shape> </item> </ripple> diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml index 06bed001ae1a..42a5d305fb65 100644 --- a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml +++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml @@ -21,6 +21,6 @@ android:viewportWidth="40" android:viewportHeight="40"> <path - android:fillColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:fillColor="@androidprv:color/materialColorOnSurfaceVariant" android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/> </vector> diff --git a/packages/SystemUI/res/drawable/volume_background_top.xml b/packages/SystemUI/res/drawable/volume_background_top.xml index 132572a41a36..7185d03a9910 100644 --- a/packages/SystemUI/res/drawable/volume_background_top.xml +++ b/packages/SystemUI/res/drawable/volume_background_top.xml @@ -17,7 +17,7 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item> <shape> - <solid android:color="?androidprv:attr/materialColorSurface" /> + <solid android:color="@androidprv:color/materialColorSurface" /> <corners android:topLeftRadius="@dimen/volume_dialog_background_corner_radius" android:topRightRadius="@dimen/volume_dialog_background_corner_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml index 7d7498feeba6..25d78e3474d5 100644 --- a/packages/SystemUI/res/drawable/volume_dialog_background.xml +++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml @@ -18,5 +18,5 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> <corners android:radius="@dimen/volume_dialog_background_corner_radius" /> - <solid android:color="?androidprv:attr/materialColorSurface" /> + <solid android:color="@androidprv:color/materialColorSurface" /> </shape> diff --git a/packages/SystemUI/res/drawable/volume_dialog_background_small_radius.xml b/packages/SystemUI/res/drawable/volume_dialog_background_small_radius.xml index 7d794966c480..9026d64aa969 100644 --- a/packages/SystemUI/res/drawable/volume_dialog_background_small_radius.xml +++ b/packages/SystemUI/res/drawable/volume_dialog_background_small_radius.xml @@ -17,5 +17,5 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> <corners android:radius="@dimen/volume_dialog_background_square_corner_radius" /> - <solid android:color="?androidprv:attr/materialColorSurface" /> + <solid android:color="@androidprv:color/materialColorSurface" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml index 131201e7a94f..555eebd77b1e 100644 --- a/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml +++ b/packages/SystemUI/res/drawable/volume_drawer_selection_bg.xml @@ -19,6 +19,6 @@ <size android:height="@dimen/volume_dialog_ringer_drawer_button_size" android:width="@dimen/volume_dialog_ringer_drawer_button_size" /> - <solid android:color="?androidprv:attr/materialColorPrimary" /> + <solid android:color="@androidprv:color/materialColorPrimary" /> <corners android:radius="@dimen/volume_dialog_ringer_selected_button_background_radius" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/volume_ringer_item_bg.xml b/packages/SystemUI/res/drawable/volume_ringer_item_bg.xml index a8c9818b58a3..4b3edb905dca 100644 --- a/packages/SystemUI/res/drawable/volume_ringer_item_bg.xml +++ b/packages/SystemUI/res/drawable/volume_ringer_item_bg.xml @@ -17,6 +17,6 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle" > <size android:width="@dimen/volume_dialog_ringer_drawer_button_size" android:height="@dimen/volume_dialog_ringer_drawer_button_size"/> - <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest" /> + <solid android:color="@androidprv:color/materialColorSurfaceContainerHighest" /> <corners android:radius="@dimen/volume_dialog_background_square_corner_radius" /> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar.xml b/packages/SystemUI/res/drawable/volume_row_seekbar.xml index d7d75d4304d0..c47d7c0e8eb1 100644 --- a/packages/SystemUI/res/drawable/volume_row_seekbar.xml +++ b/packages/SystemUI/res/drawable/volume_row_seekbar.xml @@ -26,7 +26,7 @@ <shape> <size android:height="@dimen/volume_dialog_track_width" /> <corners android:radius="@dimen/volume_dialog_panel_width_half" /> - <solid android:color="?androidprv:attr/materialColorOutlineVariant" /> + <solid android:color="@androidprv:color/materialColorOutlineVariant" /> </shape> </item> <item android:id="@android:id/progress" diff --git a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml index ca7df86d8296..3e53bf45cff8 100644 --- a/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml +++ b/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml @@ -42,7 +42,7 @@ android:layout_marginBottom="16dp" android:scaleType="fitCenter" android:src="@null" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" /> <TextView diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml index 7b7c96cb0322..afc58cc8e163 100644 --- a/packages/SystemUI/res/layout/app_clips_screenshot.xml +++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml @@ -31,10 +31,10 @@ android:layout_height="48dp" android:layout_marginStart="8dp" android:background="@drawable/overlay_button_background" - android:backgroundTint="?androidprv:attr/materialColorPrimary" + android:backgroundTint="@androidprv:color/materialColorPrimary" android:paddingHorizontal="24dp" android:text="@string/app_clips_save_add_to_note" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" app:layout_constraintBottom_toTopOf="@id/preview" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -61,7 +61,7 @@ android:button="@drawable/checkbox_circle_shape" android:checked="true" android:text="@string/backlinks_include_link" - android:textColor="?androidprv:attr/materialColorOnBackground" + android:textColor="@androidprv:color/materialColorOnBackground" android:visibility="gone" app:layout_constraintBottom_toTopOf="@id/preview" app:layout_constraintStart_toEndOf="@id/cancel" @@ -89,11 +89,11 @@ android:layout_marginStart="8dp" android:drawablePadding="4dp" android:drawableStart="@drawable/ic_info_outline" - android:drawableTint="?androidprv:attr/materialColorOnBackground" + android:drawableTint="@androidprv:color/materialColorOnBackground" android:gravity="center" android:paddingHorizontal="8dp" android:text="@string/backlinks_cross_profile_error" - android:textColor="?androidprv:attr/materialColorOnBackground" + android:textColor="@androidprv:color/materialColorOnBackground" android:visibility="gone" app:layout_constraintBottom_toTopOf="@id/preview" app:layout_constraintStart_toEndOf="@id/backlinks_data" diff --git a/packages/SystemUI/res/layout/bundle_notification_info.xml b/packages/SystemUI/res/layout/bundle_notification_info.xml index 8700832c0eb0..745066a7bdbb 100644 --- a/packages/SystemUI/res/layout/bundle_notification_info.xml +++ b/packages/SystemUI/res/layout/bundle_notification_info.xml @@ -103,7 +103,7 @@ asked for it --> android:contentDescription="@string/notification_app_settings" android:src="@drawable/ic_info" android:layout_toStartOf="@id/info" - android:tint="?androidprv:attr/materialColorPrimary"/> + android:tint="@androidprv:color/materialColorPrimary"/> <ImageButton android:id="@+id/info" android:layout_width="@dimen/notification_importance_toggle_size" @@ -112,7 +112,7 @@ asked for it --> android:contentDescription="@string/notification_more_settings" android:background="@drawable/ripple_drawable_20dp" android:src="@drawable/ic_settings" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:layout_alignParentEnd="true" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/chipbar.xml b/packages/SystemUI/res/layout/chipbar.xml index e1b8ab469765..2fecf79e926e 100644 --- a/packages/SystemUI/res/layout/chipbar.xml +++ b/packages/SystemUI/res/layout/chipbar.xml @@ -56,10 +56,10 @@ android:layout_height="wrap_content" android:layout_weight="1" style="@style/Chipbar.Text" - android:textColor="?androidprv:attr/materialColorOnSecondaryFixed" + android:textColor="@androidprv:color/materialColorOnSecondaryFixed" android:alpha="0.0" /> - <!-- LINT.ThenChange(systemui.temporarydisplay.chipbar.ChipbarInfo.kt) --> + <!-- LINT.ThenChange(/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt) --> <!-- At most one of [loading, failure_icon, undo] will be visible at a time. --> <ImageView @@ -68,7 +68,7 @@ android:layout_height="@dimen/chipbar_end_icon_size" android:layout_marginStart="@dimen/chipbar_end_item_start_margin" android:src="@drawable/ic_progress_activity" - android:tint="?androidprv:attr/materialColorOnSecondaryFixedVariant" + android:tint="@androidprv:color/materialColorOnSecondaryFixedVariant" android:alpha="0.0" /> @@ -88,7 +88,7 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/chipbar_end_item_start_margin" style="@style/Chipbar.Text" - android:textColor="?androidprv:attr/materialColorOnPrimaryFixed" + android:textColor="@androidprv:color/materialColorOnPrimaryFixed" android:paddingStart="@dimen/chipbar_outer_padding" android:paddingEnd="@dimen/chipbar_outer_padding" android:paddingTop="@dimen/chipbar_end_button_vertical_padding" diff --git a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml index 14b3b55df0a4..3378dcced537 100644 --- a/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml +++ b/packages/SystemUI/res/layout/clipboard_edit_text_activity.xml @@ -17,8 +17,8 @@ android:paddingHorizontal="16dp" android:background="@drawable/overlay_button_background" android:text="@string/clipboard_edit_text_done" - android:backgroundTint="?androidprv:attr/materialColorPrimary" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:backgroundTint="@androidprv:color/materialColorPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml index 572f063c20c4..448b3e7d5ea0 100644 --- a/packages/SystemUI/res/layout/clipboard_overlay.xml +++ b/packages/SystemUI/res/layout/clipboard_overlay.xml @@ -222,8 +222,8 @@ android:layout_height="match_parent" android:layout_margin="@dimen/overlay_dismiss_button_margin" android:background="@drawable/circular_background" - android:backgroundTint="?androidprv:attr/materialColorPrimaryFixedDim" - android:tint="?androidprv:attr/materialColorOnPrimaryFixed" + android:backgroundTint="@androidprv:color/materialColorPrimaryFixedDim" + android:tint="@androidprv:color/materialColorOnPrimaryFixed" android:padding="4dp" android:src="@drawable/ic_close"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/connected_display_dialog.xml b/packages/SystemUI/res/layout/connected_display_dialog.xml index a71782b0a109..b22355551fe3 100644 --- a/packages/SystemUI/res/layout/connected_display_dialog.xml +++ b/packages/SystemUI/res/layout/connected_display_dialog.xml @@ -30,11 +30,11 @@ android:layout_width="@dimen/connected_display_dialog_logo_size" android:layout_height="@dimen/connected_display_dialog_logo_size" android:background="@drawable/circular_background" - android:backgroundTint="?androidprv:attr/materialColorSecondary" + android:backgroundTint="@androidprv:color/materialColorSecondary" android:importantForAccessibility="no" android:padding="6dp" android:src="@drawable/stat_sys_connected_display" - android:tint="?androidprv:attr/materialColorOnSecondary" /> + android:tint="@androidprv:color/materialColorOnSecondary" /> <TextView android:id="@+id/connected_display_dialog_title" diff --git a/packages/SystemUI/res/layout/contextual_edu_dialog.xml b/packages/SystemUI/res/layout/contextual_edu_dialog.xml index 7eb6efe4afa4..09aa8daa217e 100644 --- a/packages/SystemUI/res/layout/contextual_edu_dialog.xml +++ b/packages/SystemUI/res/layout/contextual_edu_dialog.xml @@ -39,6 +39,7 @@ android:ellipsize="end" android:fontFamily="google-sans-medium" android:maxWidth="280dp" - android:textColor="?androidprv:attr/materialColorOnTertiaryFixed" - android:textSize="14sp" /> + android:textColor="@androidprv:color/materialColorOnTertiaryFixed" + android:textSize="14sp" + android:textStyle="bold" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml index 70f2cd5fcc28..2d799ae34575 100644 --- a/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml +++ b/packages/SystemUI/res/layout/hearing_devices_spinner_dropdown_view.xml @@ -28,7 +28,7 @@ android:layout_height="@dimen/hearing_devices_preset_spinner_icon_size" android:layout_gravity="center_vertical" android:layout_marginEnd="@dimen/hearing_devices_layout_margin" - android:tint="?androidprv:attr/materialColorOnPrimaryContainer" + android:tint="@androidprv:color/materialColorOnPrimaryContainer" android:src="@drawable/ic_check" android:contentDescription="@string/hearing_devices_spinner_item_selected"/> <TextView diff --git a/packages/SystemUI/res/layout/immersive_mode_cling.xml b/packages/SystemUI/res/layout/immersive_mode_cling.xml index 20b7cd3add4b..f12cf96c5597 100644 --- a/packages/SystemUI/res/layout/immersive_mode_cling.xml +++ b/packages/SystemUI/res/layout/immersive_mode_cling.xml @@ -42,7 +42,7 @@ android:layout_marginTop="20dp" android:gravity="center_horizontal" android:text="@string/immersive_cling_title" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="24sp" android:fontFamily="google-sans" /> @@ -54,7 +54,7 @@ android:paddingTop="14dp" android:gravity="center_horizontal" android:text="@string/immersive_cling_description" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textSize="14sp" android:fontFamily="google-sans" /> @@ -72,7 +72,7 @@ android:minWidth="48dp" android:minHeight="48dp" android:text="@string/immersive_cling_positive" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" android:textAllCaps="false" android:textSize="14sp" android:textFontWeight="500" 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/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml index 5ab23271922c..4a40dda4a9a8 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml @@ -40,7 +40,7 @@ android:layout_height="wrap_content" android:paddingEnd="12dp" android:paddingBottom="4dp" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="16sp" android:maxLines="5" diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml index 6e7fde68ca04..3e69a6655a27 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml @@ -21,7 +21,7 @@ android:layout_height="match_parent" android:textAppearance="?android:attr/textAppearanceMedium" android:textSize="14sp" - android:textColor="?androidprv:attr/materialColorPrimary" + android:textColor="@androidprv:color/materialColorPrimary" android:importantForAccessibility="yes" android:paddingTop="20dp" android:paddingBottom="10dp"/> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml index 8772a732e829..5bba9ba21759 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_separator_view.xml @@ -22,7 +22,7 @@ android:layout_marginLeft="0dp" android:layout_marginRight="0dp" android:text="@string/keyboard_shortcut_join" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:singleLine="true" android:gravity="center" android:textSize="@dimen/ksh_item_text_size" /> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml index 42bbf25d6c26..91558fdadb36 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml @@ -25,7 +25,7 @@ android:paddingBottom="@dimen/ksh_key_view_padding_vertical" android:layout_marginStart="@dimen/ksh_item_margin_start" android:background="@drawable/ksh_key_item_background" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:singleLine="true" android:gravity="center" android:textSize="@dimen/ksh_item_text_size" /> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml index 45a4af92339c..18716ef00815 100644 --- a/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_search_view.xml @@ -52,14 +52,14 @@ android:drawableStart="@drawable/ic_shortcutlist_search" android:drawablePadding="15dp" android:singleLine="true" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:inputType="text" android:textDirection="locale" android:textAlignment="viewStart" android:hint="@string/keyboard_shortcut_search_list_hint" android:textAppearance="@android:style/TextAppearance.Material" android:textSize="16sp" - android:textColorHint="?androidprv:attr/materialColorOutline" /> + android:textColorHint="@androidprv:color/materialColorOutline" /> <ImageButton android:id="@+id/keyboard_shortcuts_search_cancel" diff --git a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml index 636f479e5778..e47fc62c6e16 100644 --- a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml +++ b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml @@ -32,7 +32,7 @@ android:layout_width="@dimen/keyguard_settings_popup_menu_icon_height" android:layout_height="@dimen/keyguard_settings_popup_menu_icon_width" android:layout_marginEnd="@dimen/keyguard_settings_popup_menu_icon_end_margin" - android:tint="?androidprv:attr/materialColorOnSecondaryFixed" + android:tint="@androidprv:color/materialColorOnSecondaryFixed" android:importantForAccessibility="no" tools:ignore="UseAppTint" /> @@ -41,7 +41,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" - android:textColor="?androidprv:attr/materialColorOnSecondaryFixed" + android:textColor="@androidprv:color/materialColorOnSecondaryFixed" android:textSize="14sp" android:maxLines="1" android:ellipsize="end" /> diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml index 4d207da851cd..87433be45a7a 100644 --- a/packages/SystemUI/res/layout/long_screenshot.xml +++ b/packages/SystemUI/res/layout/long_screenshot.xml @@ -32,8 +32,8 @@ android:layout_marginStart="8dp" android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin" android:background="@drawable/overlay_button_background" - android:backgroundTint="?androidprv:attr/materialColorPrimary" - android:textColor="?androidprv:attr/materialColorOnPrimary" + android:backgroundTint="@androidprv:color/materialColorPrimary" + android:textColor="@androidprv:color/materialColorOnPrimary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/preview" /> @@ -47,8 +47,8 @@ android:layout_marginStart="6dp" android:layout_marginTop="@dimen/long_screenshot_action_bar_top_margin" android:background="@drawable/overlay_button_outline" - android:backgroundTint="?androidprv:attr/materialColorPrimary" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:backgroundTint="@androidprv:color/materialColorPrimary" + android:textColor="@androidprv:color/materialColorOnSurface" app:layout_constraintStart_toEndOf="@id/save" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/preview" @@ -57,7 +57,7 @@ <ImageButton android:id="@+id/share" style="@android:style/Widget.Material.Button.Borderless" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:layout_width="48dp" android:layout_height="48dp" android:layout_marginEnd="8dp" @@ -114,10 +114,10 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:handleThickness="@dimen/screenshot_crop_handle_thickness" - app:handleColor="?androidprv:attr/materialColorSecondary" - app:scrimColor="?androidprv:attr/materialColorSurfaceContainer" + app:handleColor="@androidprv:color/materialColorSecondary" + app:scrimColor="@androidprv:color/materialColorSurfaceContainer" app:scrimAlpha="128" - app:containerBackgroundColor="?androidprv:attr/materialColorSurfaceContainer" + app:containerBackgroundColor="@androidprv:color/materialColorSurfaceContainer" tools:background="?android:colorBackground" tools:minHeight="100dp" tools:minWidth="100dp" /> @@ -131,11 +131,11 @@ app:layout_constraintTop_toTopOf="@id/preview" app:layout_constraintLeft_toLeftOf="parent" app:handleThickness="@dimen/screenshot_crop_handle_thickness" - app:handleColor="?androidprv:attr/materialColorSecondary" - app:scrimColor="?androidprv:attr/materialColorSurfaceContainer" + app:handleColor="@androidprv:color/materialColorSecondary" + app:scrimColor="@androidprv:color/materialColorSurfaceContainer" app:scrimAlpha="128" app:borderThickness="4dp" - app:borderColor="?androidprv:attr/materialColorSurfaceBright" /> + app:borderColor="@androidprv:color/materialColorSurfaceBright" /> <ImageButton android:id="@+id/edit" @@ -147,7 +147,7 @@ android:background="@drawable/screenshot_edit_background" android:src="@drawable/ic_screenshot_edit" android:contentDescription="@string/screenshot_edit_label" - android:tint="?androidprv:attr/materialColorOnSecondaryFixed" + android:tint="@androidprv:color/materialColorOnSecondaryFixed" android:padding="16dp" android:scaleType="fitCenter" app:layout_constraintBottom_toBottomOf="parent" diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml index d8d298573d04..9a66ca9f3baa 100644 --- a/packages/SystemUI/res/layout/notif_half_shelf.xml +++ b/packages/SystemUI/res/layout/notif_half_shelf.xml @@ -66,7 +66,7 @@ android:gravity="center_vertical|start" android:ellipsize="end" android:maxLines="2" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textSize="16sp" /> diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml index 9ef342ce5220..b2eaa6ce92b5 100644 --- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml +++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml @@ -60,7 +60,7 @@ android:ellipsize="end" android:maxLines="1" android:fontFamily="@*android:string/config_headlineFontFamily" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:textSize="16sp" /> @@ -75,7 +75,7 @@ android:maxLines="1" android:layout_below="@id/channel_name" android:fontFamily="@*android:string/config_bodyFontFamily" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:textSize="14sp" /> </RelativeLayout> diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml b/packages/SystemUI/res/layout/notification_2025_footer.xml index 71c77a56b6a8..9b3d67f7b4a2 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml +++ b/packages/SystemUI/res/layout/notification_2025_footer.xml @@ -64,6 +64,8 @@ android:contentDescription="@string/accessibility_clear_all" android:focusable="true" android:text="@string/clear_all_notifications_text" + android:ellipsize="end" + android:maxLines="1" app:layout_constraintEnd_toStartOf="@id/settings_button" app:layout_constraintStart_toEndOf="@id/history_button" /> diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml index 13e24a9ea277..c1d94f990d25 100644 --- a/packages/SystemUI/res/layout/notification_children_divider.xml +++ b/packages/SystemUI/res/layout/notification_children_divider.xml @@ -21,4 +21,4 @@ android:id="@+id/notification_more_divider" android:layout_width="match_parent" android:layout_height="@dimen/notification_divider_height" - android:background="?androidprv:attr/materialColorOnSurfaceVariant" /> + android:background="@androidprv:color/materialColorOnSurfaceVariant" /> diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 3a752c81b95a..cb9d8115d674 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -174,7 +174,7 @@ android:contentDescription="@string/notification_more_settings" android:background="@drawable/ripple_drawable_20dp" android:src="@drawable/ic_settings" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:layout_alignParentEnd="true" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 19a3f2fd521c..edca7e3a9940 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -103,7 +103,7 @@ asked for it --> android:contentDescription="@string/notification_app_settings" android:src="@drawable/ic_info" android:layout_toStartOf="@id/info" - android:tint="?androidprv:attr/materialColorPrimary"/> + android:tint="@androidprv:color/materialColorPrimary"/> <ImageButton android:id="@+id/info" android:layout_width="@dimen/notification_importance_toggle_size" @@ -112,7 +112,7 @@ asked for it --> android:contentDescription="@string/notification_more_settings" android:background="@drawable/ripple_drawable_20dp" android:src="@drawable/ic_settings" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:layout_alignParentEnd="true" /> </LinearLayout> diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml index ce09385eaf45..f114f4cc02fa 100644 --- a/packages/SystemUI/res/layout/notification_snooze.xml +++ b/packages/SystemUI/res/layout/notification_snooze.xml @@ -23,7 +23,7 @@ android:orientation="vertical" android:paddingTop="2dp" android:paddingBottom="2dp" - android:background="?androidprv:attr/materialColorSurfaceContainerHigh" + android:background="@androidprv:color/materialColorSurfaceContainerHigh" android:theme="@style/Theme.SystemUI"> <RelativeLayout @@ -38,7 +38,7 @@ android:layout_alignParentStart="true" android:layout_centerVertical="true" android:paddingStart="@*android:dimen/notification_content_margin_end" - android:textColor="?androidprv:attr/materialColorOnSurface" + android:textColor="@androidprv:color/materialColorOnSurface" android:paddingEnd="4dp"/> <ImageView diff --git a/packages/SystemUI/res/layout/notification_snooze_option.xml b/packages/SystemUI/res/layout/notification_snooze_option.xml index fa6f965198d4..364b44c97d61 100644 --- a/packages/SystemUI/res/layout/notification_snooze_option.xml +++ b/packages/SystemUI/res/layout/notification_snooze_option.xml @@ -23,4 +23,4 @@ android:layout_marginEnd="@*android:dimen/notification_content_margin_end" android:gravity="center_vertical" android:textSize="14sp" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"/>
\ No newline at end of file + android:textColor="@androidprv:color/materialColorOnSurfaceVariant"/>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml b/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml index b84f3a9794be..3ca4b94d3003 100644 --- a/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml +++ b/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml @@ -25,7 +25,7 @@ android:foreground="?android:attr/selectableItemBackground" app:cardCornerRadius="28dp" app:cardElevation="0dp" - app:cardBackgroundColor="?androidprv:attr/materialColorSurfaceBright"> + app:cardBackgroundColor="@androidprv:color/materialColorSurfaceBright"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/privacy_dialog_v2.xml b/packages/SystemUI/res/layout/privacy_dialog_v2.xml index 76098a1ab486..0392322aa1c1 100644 --- a/packages/SystemUI/res/layout/privacy_dialog_v2.xml +++ b/packages/SystemUI/res/layout/privacy_dialog_v2.xml @@ -45,7 +45,7 @@ android:layout_height="wrap_content" android:text="@string/privacy_dialog_summary" android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?androidprv:attr/materialColorOnSurfaceVariant" + android:textColor="@androidprv:color/materialColorOnSurfaceVariant" android:gravity="center" android:layout_marginBottom="20dp"/> </LinearLayout> diff --git a/packages/SystemUI/res/layout/record_issue_dialog.xml b/packages/SystemUI/res/layout/record_issue_dialog.xml index b2a8c4ce96db..76a7d3432380 100644 --- a/packages/SystemUI/res/layout/record_issue_dialog.xml +++ b/packages/SystemUI/res/layout/record_issue_dialog.xml @@ -55,7 +55,7 @@ android:layout_height="@dimen/screenrecord_option_icon_size" android:layout_weight="0" android:src="@drawable/ic_screenrecord" - app:tint="?androidprv:attr/materialColorOnSurface" + app:tint="@androidprv:color/materialColorOnSurface" android:importantForAccessibility="no" android:layout_gravity="center" android:layout_marginEnd="@dimen/screenrecord_option_padding" /> @@ -95,7 +95,7 @@ android:layout_height="@dimen/screenrecord_option_icon_size" android:layout_weight="0" android:src="@drawable/ic_bugreport" - app:tint="?androidprv:attr/materialColorOnSurface" + app:tint="@androidprv:color/materialColorOnSurface" android:importantForAccessibility="no" android:layout_gravity="center" android:layout_marginEnd="@dimen/screenrecord_option_padding" /> diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml index 0533c7e3fc50..78d1ab25ffa9 100644 --- a/packages/SystemUI/res/layout/screen_share_dialog.xml +++ b/packages/SystemUI/res/layout/screen_share_dialog.xml @@ -36,7 +36,7 @@ android:layout_width="@dimen/screenrecord_logo_size" android:layout_height="@dimen/screenrecord_logo_size" android:src="@drawable/ic_media_projection_permission" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" android:importantForAccessibility="no"/> <TextView android:id="@+id/screen_share_dialog_title" diff --git a/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml b/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml index 8c31713a5e34..1ef010b62d81 100644 --- a/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml +++ b/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml @@ -39,6 +39,6 @@ android:ellipsize="marquee" android:singleLine="true" android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?androidprv:attr/materialColorError" /> + android:textColor="@androidprv:color/materialColorError" /> </LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml index fff1de7c1049..f03c0323a7b7 100644 --- a/packages/SystemUI/res/layout/screenshot_shelf.xml +++ b/packages/SystemUI/res/layout/screenshot_shelf.xml @@ -127,8 +127,8 @@ android:layout_height="match_parent" android:layout_margin="@dimen/overlay_dismiss_button_margin" android:background="@drawable/circular_background" - android:backgroundTint="?androidprv:attr/materialColorPrimary" - android:tint="?androidprv:attr/materialColorOnPrimary" + android:backgroundTint="@androidprv:color/materialColorPrimary" + android:tint="@androidprv:color/materialColorOnPrimary" android:padding="4dp" android:src="@drawable/ic_close"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml index 39ec09b14157..980387176cff 100644 --- a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml +++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml @@ -38,8 +38,8 @@ android:layout_height="24dp" android:layout_gravity="center" android:background="@drawable/circular_background" - android:backgroundTint="?androidprv:attr/materialColorSurfaceContainerHigh" - android:tint="?androidprv:attr/materialColorOnSurface" + android:backgroundTint="@androidprv:color/materialColorSurfaceContainerHigh" + android:tint="@androidprv:color/materialColorOnSurface" android:padding="2dp" android:src="@drawable/ic_close"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/shelf_action_chip.xml b/packages/SystemUI/res/layout/shelf_action_chip.xml index 1c65e366d619..430e9f742a07 100644 --- a/packages/SystemUI/res/layout/shelf_action_chip.xml +++ b/packages/SystemUI/res/layout/shelf_action_chip.xml @@ -27,7 +27,7 @@ > <ImageView android:id="@+id/overlay_action_chip_icon" - android:tint="?androidprv:attr/materialColorOnSecondary" + android:tint="@androidprv:color/materialColorOnSecondary" android:tintMode="src_in" android:layout_width="@dimen/overlay_action_chip_icon_size" android:layout_height="@dimen/overlay_action_chip_icon_size"/> @@ -37,5 +37,5 @@ android:layout_height="wrap_content" android:fontFamily="@*android:string/config_headlineFontFamilyMedium" android:textSize="@dimen/overlay_action_chip_text_size" - android:textColor="?androidprv:attr/materialColorOnSecondary"/> + android:textColor="@androidprv:color/materialColorOnSecondary"/> </LinearLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index b8544a64d9da..a3bad8f012ac 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -58,7 +58,7 @@ android:contentDescription="@string/accessibility_volume_settings" android:soundEffectsEnabled="false" android:src="@drawable/horizontal_ellipsis" - android:tint="?androidprv:attr/materialColorPrimary" + android:tint="@androidprv:color/materialColorPrimary" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" @@ -79,4 +79,4 @@ app:layout_constraintEnd_toStartOf="@id/volume_dialog_background" app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" /> -</androidx.constraintlayout.motion.widget.MotionLayout>
\ No newline at end of file +</androidx.constraintlayout.motion.widget.MotionLayout> 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/layout/volume_ringer_button.xml b/packages/SystemUI/res/layout/volume_ringer_button.xml index 38bb783c2920..e65d0b938b65 100644 --- a/packages/SystemUI/res/layout/volume_ringer_button.xml +++ b/packages/SystemUI/res/layout/volume_ringer_button.xml @@ -26,7 +26,7 @@ android:layout_marginBottom="@dimen/volume_dialog_components_spacing" android:contentDescription="@string/volume_ringer_mode" android:gravity="center" - android:tint="?androidprv:attr/materialColorOnSurface" + android:tint="@androidprv:color/materialColorOnSurface" android:src="@drawable/volume_ringer_item_bg" android:background="@drawable/volume_ringer_item_bg"/> 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-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml index 73812c965a17..ae0006fbbf73 100644 --- a/packages/SystemUI/res/values-land/styles.xml +++ b/packages/SystemUI/res/values-land/styles.xml @@ -43,21 +43,21 @@ <item name="android:layout_marginTop">6dp</item> <item name="android:textSize">36dp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Subtitle"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">6dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Description"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">6dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> </resources> 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-sw600dp-land/styles.xml b/packages/SystemUI/res/values-sw600dp-land/styles.xml index cde1a1373bed..45698f78d03a 100644 --- a/packages/SystemUI/res/values-sw600dp-land/styles.xml +++ b/packages/SystemUI/res/values-sw600dp-land/styles.xml @@ -22,20 +22,20 @@ <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">36sp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Subtitle"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Description"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> </resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/styles.xml b/packages/SystemUI/res/values-sw600dp-port/styles.xml index 85e7af6ee1de..8b3e6fde0b74 100644 --- a/packages/SystemUI/res/values-sw600dp-port/styles.xml +++ b/packages/SystemUI/res/values-sw600dp-port/styles.xml @@ -30,7 +30,7 @@ <item name="android:layout_marginTop">24dp</item> <item name="android:textSize">36sp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-land/styles.xml b/packages/SystemUI/res/values-sw720dp-land/styles.xml index e75173d152b0..451a9a901cce 100644 --- a/packages/SystemUI/res/values-sw720dp-land/styles.xml +++ b/packages/SystemUI/res/values-sw720dp-land/styles.xml @@ -22,21 +22,21 @@ <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">36sp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Subtitle"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Description"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">16dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/styles.xml b/packages/SystemUI/res/values-sw720dp-port/styles.xml index 85e7af6ee1de..8b3e6fde0b74 100644 --- a/packages/SystemUI/res/values-sw720dp-port/styles.xml +++ b/packages/SystemUI/res/values-sw720dp-port/styles.xml @@ -30,7 +30,7 @@ <item name="android:layout_marginTop">24dp</item> <item name="android:textSize">36sp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> </resources> 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/colors.xml b/packages/SystemUI/res/values/colors.xml index a3752640e7ed..28df2e2a1b8c 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -124,7 +124,7 @@ <!-- Keyboard shortcuts colors --> <color name="ksh_application_group_color">#fff44336</color> <color name="ksh_key_item_color">@*android:color/system_on_surface_variant_light</color> - <color name="ksh_key_item_background">?androidprv:attr/materialColorSurfaceContainerHighest</color> + <color name="ksh_key_item_background">@androidprv:color/materialColorSurfaceContainerHighest</color> <color name="instant_apps_color">#ff4d5a64</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 478050b0ed85..5894f297d2a7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -237,6 +237,9 @@ <dimen name="status_bar_connected_device_bt_indicator_size">17dp</dimen> <!-- Height of a small notification in the status bar (2025 redesign version) --> + <dimen name="notification_2025_header_height">@*android:dimen/notification_2025_header_height</dimen> + + <!-- Height of a small notification in the status bar (2025 redesign version) --> <dimen name="notification_2025_min_height">@*android:dimen/notification_2025_min_height</dimen> <!-- Height of a small notification in the status bar--> @@ -1221,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..ff459e92ca28 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/> @@ -1948,6 +1950,21 @@ <!-- Text displayed indicating that the user might be able to use satellite SOS. --> <string name="satellite_emergency_only_carrier_text">Emergency calls or SOS</string> + <!-- Content description skeleton. Input strings should be carrier name and signal bar description [CHAR LIMIT=NONE]--> + <string name="accessibility_phone_string_format"><xliff:g id="carrier_name" example="Carrier Name">%1$s</xliff:g>, <xliff:g id="signal_strength_description" example="two bars">%2$s</xliff:g>.</string> + <!-- Content description describing 0 signal bars. [CHAR LIMIT=NONE] --> + <string name="accessibility_no_signal">no signal</string> + <!-- Content description describing 1 signal bar. [CHAR LIMIT=NONE] --> + <string name="accessibility_one_bar">one bar</string> + <!-- Content description describing 2 signal bars. [CHAR LIMIT=NONE] --> + <string name="accessibility_two_bars">two bars</string> + <!-- Content description describing 3 signal bars. [CHAR LIMIT=NONE] --> + <string name="accessibility_three_bars">three bars</string> + <!-- Content description describing 4 signal bars. [CHAR LIMIT=NONE] --> + <string name="accessibility_four_bars">four bars</string> + <!-- Content description describing full signal bars. [CHAR LIMIT=NONE] --> + <string name="accessibility_signal_full">signal full</string> + <!-- Accessibility label for managed profile icon (not shown on screen) [CHAR LIMIT=NONE] --> <string name="accessibility_managed_profile">Work profile</string> @@ -2280,11 +2297,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/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 9aa71374fb8e..12f6e6958b42 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -151,7 +151,7 @@ <style name="TextAppearance.QS.UserSwitcher"> <item name="android:textSize">@dimen/qs_tile_text_size</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> </style> <!-- This is hard coded to be sans-serif-condensed to match the icons --> @@ -183,67 +183,46 @@ <item name="android:textColor">?android:attr/textColorPrimary</item> </style> - <style name="TextAppearance.AuthCredential.OldTitle"> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:paddingTop">12dp</item> - <item name="android:paddingHorizontal">24dp</item> - <item name="android:textSize">24sp</item> - </style> - - <style name="TextAppearance.AuthCredential.OldSubtitle"> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:paddingTop">8dp</item> - <item name="android:paddingHorizontal">24dp</item> - <item name="android:textSize">16sp</item> - </style> - - <style name="TextAppearance.AuthCredential.OldDescription"> - <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:paddingTop">8dp</item> - <item name="android:paddingHorizontal">24dp</item> - <item name="android:textSize">14sp</item> - </style> - <style name="TextAppearance.AuthCredential.LogoDescription" parent="TextAppearance.Material3.LabelLarge" > <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> - <item name="android:gravity">@integer/biometric_dialog_text_gravity</item> + <item name="android:gravity">center_horizontal</item> <item name="android:maxLines">1</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:ellipsize">end</item> </style> <style name="TextAppearance.AuthCredential.Title" parent="TextAppearance.Material3.HeadlineSmall" > <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthCredential.Subtitle" parent="TextAppearance.Material3.BodyMedium" > <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthCredential.Description" parent="TextAppearance.Material3.BodyMedium" > <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthCredential.VerticalListContentViewDescription" parent="TextAppearance.Material3.TitleSmall"> <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthCredential.ContentViewWithButtonDescription" parent="TextAppearance.AuthCredential.Description" /> <style name="TextAppearance.AuthCredential.ContentViewListItem" parent="TextAppearance.Material3.BodySmall"> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:paddingTop">@dimen/biometric_prompt_content_list_item_padding_top</item> <item name="android:breakStrategy">high_quality</item> </style> <style name="TextAppearance.AuthCredential.Indicator" parent="TextAppearance.Material3.BodyMedium"> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:marqueeRepeatLimit">marquee_forever</item> <item name="android:singleLine">true</item> <item name="android:ellipsize">marquee</item> @@ -269,21 +248,21 @@ <item name="android:layout_marginTop">24dp</item> <item name="android:textSize">36dp</item> <item name="android:focusable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Subtitle"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">20dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Description"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:layout_marginTop">20dp</item> <item name="android:textSize">18sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.AuthNonBioCredential.Error"> @@ -352,7 +331,7 @@ </style> <style name="AuthNonCredentialPanelStyle"> - <item name="android:background">?androidprv:attr/materialColorSurfaceBright</item> + <item name="android:background">@androidprv:color/materialColorSurfaceBright</item> </style> <style name="AuthCredentialPanelStyle" parent="AuthNonCredentialPanelStyle"> @@ -383,13 +362,13 @@ <item name="android:minWidth">48dp</item> <item name="android:paddingLeft">0dp</item> <item name="android:paddingRight">12dp</item> - <item name="android:textColor">?androidprv:attr/materialColorPrimary</item> + <item name="android:textColor">@androidprv:color/materialColorPrimary</item> </style> <style name="AuthCredentialNegativeButtonStyle" parent="TextAppearance.Material3.LabelLarge"> <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> <item name="android:background">@color/transparent</item> - <item name="android:textColor">?androidprv:attr/materialColorPrimary</item> + <item name="android:textColor">@androidprv:color/materialColorPrimary</item> </style> <style name="DeviceManagementDialogTitle"> @@ -411,7 +390,7 @@ </style> <style name="KeyboardShortcutHelper.BottomSheet.DragHandle" parent="Widget.Material3.BottomSheet.DragHandle"> - <item name="tint">?androidprv:attr/materialColorOutlineVariant</item> + <item name="tint">@androidprv:color/materialColorOutlineVariant</item> </style> <style name="KeyboardShortcutHelper.BottomSheetDialogAnimation"> @@ -510,23 +489,23 @@ <item name="android:windowIsFloating">true</item> <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item> - <item name="surfaceBright">?androidprv:attr/materialColorSurfaceBright</item> + <item name="surfaceBright">@androidprv:color/materialColorSurfaceBright</item> <item name="android:colorBackground">?attr/surfaceBright</item> - <item name="scHigh">?androidprv:attr/materialColorSurfaceContainerHigh</item> - <item name="primary">?androidprv:attr/materialColorPrimary</item> - <item name="tertiary">?androidprv:attr/materialColorTertiary</item> - <item name="onSurface">?androidprv:attr/materialColorOnSurface</item> - <item name="onSurfaceVariant">?androidprv:attr/materialColorOnSurfaceVariant</item> - <item name="outline">?androidprv:attr/materialColorOutline</item> - - <item name="shadeActive">?androidprv:attr/customColorShadeActive</item> - <item name="onShadeActive">?androidprv:attr/customColorOnShadeActive</item> - <item name="onShadeActiveVariant">?androidprv:attr/customColorOnShadeActiveVariant</item> - <item name="shadeInactive">?androidprv:attr/customColorShadeInactive</item> - <item name="onShadeInactive">?androidprv:attr/customColorOnShadeInactive</item> - <item name="onShadeInactiveVariant">?androidprv:attr/customColorOnShadeInactiveVariant</item> - <item name="shadeDisabled">?androidprv:attr/customColorShadeDisabled</item> - <item name="underSurface">?androidprv:attr/customColorUnderSurface</item> + <item name="scHigh">@androidprv:color/materialColorSurfaceContainerHigh</item> + <item name="primary">@androidprv:color/materialColorPrimary</item> + <item name="tertiary">@androidprv:color/materialColorTertiary</item> + <item name="onSurface">@androidprv:color/materialColorOnSurface</item> + <item name="onSurfaceVariant">@androidprv:color/materialColorOnSurfaceVariant</item> + <item name="outline">@androidprv:color/materialColorOutline</item> + + <item name="shadeActive">@androidprv:color/customColorShadeActive</item> + <item name="onShadeActive">@androidprv:color/customColorOnShadeActive</item> + <item name="onShadeActiveVariant">@androidprv:color/customColorOnShadeActiveVariant</item> + <item name="shadeInactive">@androidprv:color/customColorShadeInactive</item> + <item name="onShadeInactive">@androidprv:color/customColorOnShadeInactive</item> + <item name="onShadeInactiveVariant">@androidprv:color/customColorOnShadeInactiveVariant</item> + <item name="shadeDisabled">@androidprv:color/customColorShadeDisabled</item> + <item name="underSurface">@androidprv:color/customColorUnderSurface</item> <item name="android:itemTextAppearance">@style/Control.MenuItem</item> </style> @@ -588,7 +567,7 @@ <item name="android:buttonBarPositiveButtonStyle">@style/Widget.Dialog.Button</item> <item name="android:buttonBarNegativeButtonStyle">@style/Widget.Dialog.Button.BorderButton</item> <item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item> - <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceBright</item> + <item name="android:colorBackground">@androidprv:color/materialColorSurfaceBright</item> <item name="android:alertDialogStyle">@style/ScrollableAlertDialogStyle</item> <item name="android:buttonBarStyle">@style/ButtonBarStyle</item> <item name="android:buttonBarButtonStyle">@style/Widget.Dialog.Button.Large</item> @@ -744,34 +723,34 @@ <style name="TextAppearance.NotificationImportanceChannel"> <item name="android:textSize">@dimen/notification_importance_channel_text</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textSize">@dimen/notification_importance_channel_text</item> </style> <style name="TextAppearance.NotificationImportanceChannelGroup"> <item name="android:textSize">@dimen/notification_importance_channel_group_text</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textSize">@dimen/notification_importance_channel_group_text</item> </style> <style name="TextAppearance.NotificationImportanceApp"> <item name="android:textSize">@dimen/notification_importance_channel_group_text</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:textSize">@dimen/notification_importance_channel_group_text</item> </style> <style name="TextAppearance.NotificationImportanceHeader"> <item name="android:textSize">@dimen/notification_importance_header_text</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.NotificationImportanceDetail"> <item name="android:textSize">@dimen/notification_importance_description_text</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:gravity">center</item> </style> @@ -785,7 +764,7 @@ <style name="TextAppearance.NotificationSectionHeaderLabel" parent="@android:style/Widget.DeviceDefault.Button.Borderless"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> <item name="android:minWidth">0dp</item> @@ -794,7 +773,7 @@ <style name="TextAppearance.NotificationSectionHeaderButton" parent="@android:style/Widget.DeviceDefault.Button.Borderless"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> <item name="android:minWidth">0dp</item> @@ -803,7 +782,7 @@ <style name="TextAppearance.NotificationFooterButton" parent="@android:style/Widget.DeviceDefault.Button.Borderless"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> <item name="android:minWidth">0dp</item> @@ -812,8 +791,8 @@ <style name="TextAppearance.NotificationFooterButtonRedesign" parent="@android:style/Widget.DeviceDefault.Button.Borderless"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> - <item name="android:drawableTint">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> + <item name="android:drawableTint">@androidprv:color/materialColorOnSurface</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">16sp</item> <item name="android:minWidth">0dp</item> @@ -1009,12 +988,12 @@ </style> <style name="LongScreenshotActivity" parent="@android:style/Theme.DeviceDefault.DayNight"> - <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceContainer</item> + <item name="android:colorBackground">@androidprv:color/materialColorSurfaceContainer</item> <item name="android:windowNoTitle">true</item> <item name="android:windowLightStatusBar">true</item> <item name="android:windowLightNavigationBar">true</item> - <item name="android:statusBarColor">?androidprv:attr/materialColorSurfaceContainer</item> - <item name="android:navigationBarColor">?androidprv:attr/materialColorSurfaceContainerHighest</item> + <item name="android:statusBarColor">@androidprv:color/materialColorSurfaceContainer</item> + <item name="android:navigationBarColor">@androidprv:color/materialColorSurfaceContainerHighest</item> <item name="android:windowActivityTransitions">true</item> </style> @@ -1092,7 +1071,7 @@ <style name="Theme.VolumePanel.Popup" parent="@style/Theme.SystemUI.Dialog"> <item name="android:dialogCornerRadius">44dp</item> - <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceContainerHigh + <item name="android:colorBackground">@androidprv:color/materialColorSurfaceContainerHigh </item> </style> @@ -1303,7 +1282,7 @@ </style> <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textSize">@dimen/dialog_title_text_size</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:lineHeight">32sp</item> @@ -1313,7 +1292,7 @@ </style> <style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium"> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> <item name="android:textSize">14sp</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:lineHeight">20sp</item> @@ -1408,7 +1387,7 @@ <style name="InternetDialog.NetworkTitle.Active"> <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Active</item> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimaryContainer</item> </style> <style name="InternetDialog.NetworkSummary"> @@ -1421,27 +1400,27 @@ <style name="InternetDialog.NetworkSummary.Active"> <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary.Active </item> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimaryContainer</item> </style> <style name="TextAppearance.InternetDialog"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textSize">16sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:textDirection">locale</item> </style> <style name="TextAppearance.InternetDialog.Secondary"> <item name="android:textSize">14sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> </style> <style name="TextAppearance.InternetDialog.Active"> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimaryContainer</item> </style> <style name="TextAppearance.InternetDialog.Secondary.Active"> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimaryContainer</item> </style> <style name="FgsManagerDialogTitle"> @@ -1478,18 +1457,18 @@ <item name="android:orientation">horizontal</item> <item name="android:focusable">true</item> <item name="android:clickable">true</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.BluetoothTileDialog"> <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:textDirection">locale</item> <item name="android:textAlignment">gravity</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.BluetoothTileDialog.Active"> - <item name="android:textColor">?androidprv:attr/materialColorOnPrimaryContainer</item> + <item name="android:textColor">@androidprv:color/materialColorOnPrimaryContainer</item> </style> <style name="BluetoothTileDialog.AudioSharingButton" parent="Widget.Dialog.Button"> @@ -1686,7 +1665,7 @@ <style name="ShortCutButton" parent="@android:style/Widget.Material.Button"> <item name="android:background">@drawable/shortcut_button_colored</item> <item name="android:textSize">16sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> <item name="android:layout_marginEnd">12dp</item> <item name="android:paddingLeft">24dp</item> <item name="android:paddingRight">24dp</item> @@ -1712,18 +1691,18 @@ parent="@android:style/TextAppearance.DeviceDefault.Medium"> <item name="android:textSize">14sp</item> <item name="android:lineHeight">20sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurface</item> </style> <style name="TextAppearance.PrivacyDialog.Item.Summary" parent="@android:style/TextAppearance.DeviceDefault.Small"> <item name="android:textSize">14sp</item> <item name="android:lineHeight">20sp</item> - <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item> + <item name="android:textColor">@androidprv:color/materialColorOnSurfaceVariant</item> </style> <style name="Theme.PrivacyDialog" parent="@style/Theme.SystemUI.Dialog"> - <item name="android:colorBackground">?androidprv:attr/materialColorSurfaceContainer</item> + <item name="android:colorBackground">@androidprv:color/materialColorSurfaceContainer</item> </style> <style name="Theme.SystemUI.Dialog.StickyKeys" parent="@style/Theme.SystemUI.Dialog"> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java index 9e8cabf141ed..8576a6ebac42 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java @@ -330,6 +330,11 @@ public class Task { } @Override + public int hashCode() { + return key.hashCode(); + } + + @Override public String toString() { return "[" + key.toString() + "] " + title; } diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt index 495367b69123..842efa3d68d0 100644 --- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt +++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt @@ -25,7 +25,6 @@ import android.content.res.ColorStateList import android.util.AttributeSet import android.view.View import com.android.app.animation.Interpolators -import com.android.settingslib.Utils import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.TITLE /** Displays security messages for the keyguard bouncer. */ @@ -71,12 +70,12 @@ open class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) : } override fun onThemeChanged() { - mDefaultColorState = getColorInStyle() ?: Utils.getColorAttr(context, TITLE) + mDefaultColorState = getColorInStyle() ?: ColorStateList.valueOf(context.getColor(TITLE)) super.onThemeChanged() } override fun reloadColor() { - mDefaultColorState = getColorInStyle() ?: Utils.getColorAttr(context, TITLE) + mDefaultColorState = getColorInStyle() ?: ColorStateList.valueOf(context.getColor(TITLE)) super.reloadColor() } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index fcaccd27a567..36afe1e0fe18 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -346,8 +346,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout { setPadding(getPaddingLeft(), getPaddingTop() + getResources().getDimensionPixelSize( R.dimen.keyguard_security_container_padding_top), getPaddingRight(), getPaddingBottom()); - setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(), - com.android.internal.R.attr.materialColorSurfaceDim)); + setBackgroundColor( + getContext().getColor(com.android.internal.R.color.materialColorSurfaceDim)); } void onResume(SecurityMode securityMode, boolean faceAuthEnabled) { @@ -814,8 +814,8 @@ public class KeyguardSecurityContainer extends ConstraintLayout { void reloadColors() { mViewMode.reloadColors(); - setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(), - com.android.internal.R.attr.materialColorSurfaceDim)); + setBackgroundColor(getContext().getColor( + com.android.internal.R.color.materialColorSurfaceDim)); } /** Handles density or font scale changes. */ diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt index 392abf2aa82c..0942353a7110 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimInputView.kt @@ -20,7 +20,6 @@ import android.content.Context import android.util.AttributeSet import android.widget.ImageView import androidx.core.graphics.drawable.DrawableCompat -import com.android.settingslib.Utils import com.android.systemui.res.R import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.EMERGENCY_BUTTON @@ -45,7 +44,7 @@ abstract class KeyguardSimInputView(context: Context, attrs: AttributeSet) : override fun reloadColors() { super.reloadColors() - val imageColor = Utils.getColorAttrDefaultColor(context, EMERGENCY_BUTTON) + val imageColor = context.getColor(EMERGENCY_BUTTON) simImageView?.let { val wrappedDrawable = DrawableCompat.wrap(it.drawable) DrawableCompat.setTint(wrappedDrawable, imageColor) diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java index e77341651a8e..aed1c10ead24 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java @@ -15,21 +15,17 @@ */ package com.android.keyguard; -import static com.android.settingslib.Utils.getColorAttrDefaultColor; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BACKGROUND_PRESSED; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_BUTTON; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_KEY; import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.ColorId.NUM_PAD_PRESSED; -import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset; import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.content.Context; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.view.ContextThemeWrapper; @@ -126,18 +122,15 @@ class NumPadAnimator { int[] customAttrs = {android.R.attr.colorControlNormal}; ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle); - @SuppressLint("ResourceType") TypedArray a = ctw.obtainStyledAttributes(customAttrs); - mNormalBackgroundColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0, - NUM_PAD_BACKGROUND); - a.recycle(); + mNormalBackgroundColor = ctw.getColor(NUM_PAD_BACKGROUND); - mPressedBackgroundColor = getColorAttrDefaultColor(context, NUM_PAD_BACKGROUND_PRESSED); - mTextColorPressed = getColorAttrDefaultColor(context, NUM_PAD_PRESSED); + mPressedBackgroundColor = context.getColor(NUM_PAD_BACKGROUND_PRESSED); + mTextColorPressed = context.getColor(NUM_PAD_PRESSED); mBackground.setColor(mNormalBackgroundColor); mTextColorPrimary = isNumPadKey - ? getColorAttrDefaultColor(context, NUM_PAD_KEY) - : getColorAttrDefaultColor(context, NUM_PAD_BUTTON); + ? context.getColor(NUM_PAD_KEY) + : context.getColor(NUM_PAD_BUTTON); createAnimators(); } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java index a81c1b0bf9c3..d7799bf505bd 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java @@ -30,7 +30,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.Nullable; -import com.android.settingslib.Utils; import com.android.systemui.res.R; /** @@ -101,7 +100,7 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni if (mAnimator != null) mAnimator.reloadColors(getContext()); int textColorResId = mIsTransparentMode ? NUM_PAD_KEY : NUM_PAD_BUTTON; - int imageColor = Utils.getColorAttrDefaultColor(getContext(), textColorResId); + int imageColor = getContext().getColor(textColorResId); ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor)); } diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java index ebde8a3057ce..e8a702f5fca3 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java @@ -155,8 +155,7 @@ public class NumPadKey extends ViewGroup implements NumPadAnimationListener { * Reload colors from resources. **/ public void reloadColors() { - int textColor = Utils.getColorAttr(getContext(), NUM_PAD_KEY) - .getDefaultColor(); + int textColor = getContext().getColor(NUM_PAD_KEY); int klondikeColor = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary) .getDefaultColor(); mDigitText.setTextColor(textColor); diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java index 5e9eed98f97b..bac9dacef9e1 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeHintingView.java @@ -28,7 +28,6 @@ import android.widget.LinearLayout; import androidx.core.graphics.drawable.DrawableCompat; -import com.android.settingslib.Utils; import com.android.systemui.res.R; /** @@ -39,8 +38,7 @@ public class PinShapeHintingView extends LinearLayout implements PinShapeInput { private int mPinLength; private int mDotDiameter; - private int mColor = Utils.getColorAttr(getContext(), PIN_SHAPES) - .getDefaultColor(); + private int mColor = getContext().getColor(PIN_SHAPES); private int mPosition = 0; private static final int DEFAULT_PIN_LENGTH = 6; private PinShapeAdapter mPinShapeAdapter; diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java index ee70de3e86a0..26a774e991a0 100644 --- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java +++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java @@ -39,7 +39,6 @@ import android.widget.LinearLayout; import androidx.core.graphics.drawable.DrawableCompat; import com.android.app.animation.Interpolators; -import com.android.settingslib.Utils; import com.android.systemui.res.R; /** @@ -49,7 +48,7 @@ import com.android.systemui.res.R; public class PinShapeNonHintingView extends LinearLayout implements PinShapeInput { private static final int RESET_STAGGER_DELAY = 40; private static final int RESET_MAX_DELAY = 200; - private int mColor = Utils.getColorAttr(getContext(), PIN_SHAPES).getDefaultColor(); + private int mColor = getContext().getColor(PIN_SHAPES); private int mPosition = 0; private boolean mIsAnimatingReset = false; private final PinShapeAdapter mPinShapeAdapter; diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags index 08236b7e280a..ca5424bc0c52 100644 --- a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags +++ b/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.systemui; diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt index 3abcb139ab5c..11ce168b9bcb 100644 --- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt @@ -32,7 +32,6 @@ import android.view.View import androidx.core.graphics.ColorUtils import com.android.app.animation.Interpolators import com.android.keyguard.KeyguardUpdateMonitor -import com.android.settingslib.Utils import com.android.systemui.biometrics.AuthController import com.android.systemui.log.ScreenDecorationsLogger import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -60,8 +59,8 @@ class FaceScanningOverlay( private val rimRect = RectF() private var cameraProtectionColor = Color.BLACK - var faceScanningAnimColor = Utils.getColorAttrDefaultColor(context, - com.android.internal.R.attr.materialColorPrimaryFixed) + var faceScanningAnimColor = + context.getColor(com.android.internal.R.color.materialColorPrimaryFixed) private var cameraProtectionAnimator: ValueAnimator? = null var hideOverlayRunnable: Runnable? = null diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java index 559e6f767f7b..ffb5f3d47bcc 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java @@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT; import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY; import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE; +import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; @@ -42,6 +43,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.View; +import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; @@ -75,6 +77,9 @@ class MenuInfoRepository { private final Context mContext; private final Configuration mConfiguration; + private final AccessibilityManager mAccessibilityManager; + private final AccessibilityManager.AccessibilityServicesStateChangeListener + mA11yServicesStateChangeListener = manager -> onTargetFeaturesChanged(); private final Handler mHandler = new Handler(Looper.getMainLooper()); private final OnSettingsContentsChanged mSettingsContentsCallback; private final SecureSettings mSecureSettings; @@ -142,9 +147,10 @@ class MenuInfoRepository { } }; - MenuInfoRepository(Context context, + MenuInfoRepository(Context context, AccessibilityManager accessibilityManager, OnSettingsContentsChanged settingsContentsChanged, SecureSettings secureSettings) { mContext = context; + mAccessibilityManager = accessibilityManager; mConfiguration = new Configuration(context.getResources().getConfiguration()); mSettingsContentsCallback = settingsContentsChanged; mSecureSettings = secureSettings; @@ -238,6 +244,13 @@ class MenuInfoRepository { mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS), /* notifyForDescendants */ false, mMenuTargetFeaturesContentObserver, UserHandle.USER_CURRENT); + if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { + mSecureSettings.registerContentObserverForUserSync( + mSecureSettings.getUriFor(ENABLED_ACCESSIBILITY_SERVICES), + /* notifyForDescendants */ false, + mMenuTargetFeaturesContentObserver, + UserHandle.USER_CURRENT); + } mSecureSettings.registerContentObserverForUserSync( mSecureSettings.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE), /* notifyForDescendants */ false, mMenuSizeContentObserver, @@ -251,6 +264,11 @@ class MenuInfoRepository { /* notifyForDescendants */ false, mMenuFadeOutContentObserver, UserHandle.USER_CURRENT); mContext.registerComponentCallbacks(mComponentCallbacks); + + if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { + mAccessibilityManager.addAccessibilityServicesStateChangeListener( + mA11yServicesStateChangeListener); + } } void unregisterObserversAndCallbacks() { @@ -258,6 +276,11 @@ class MenuInfoRepository { mContext.getContentResolver().unregisterContentObserver(mMenuSizeContentObserver); mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver); mContext.unregisterComponentCallbacks(mComponentCallbacks); + + if (!com.android.systemui.Flags.floatingMenuNarrowTargetContentObserver()) { + mAccessibilityManager.removeAccessibilityServicesStateChangeListener( + mA11yServicesStateChangeListener); + } } interface OnSettingsContentsChanged { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java index cfcaa4fea99b..cb96e7859fba 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java @@ -42,7 +42,8 @@ class MenuViewLayerController implements IAccessibilityFloatingMenu { NavigationModeController navigationModeController) { mWindowManager = viewCaptureAwareWindowManager; - MenuViewModel menuViewModel = new MenuViewModel(context, secureSettings); + MenuViewModel menuViewModel = new MenuViewModel( + context, accessibilityManager, secureSettings); MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context, windowManager); mMenuViewLayer = new MenuViewLayer(context, windowManager, accessibilityManager, diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java index 46c407e24fe2..f924784a5535 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java @@ -17,6 +17,7 @@ package com.android.systemui.accessibility.floatingmenu; import android.content.Context; +import android.view.accessibility.AccessibilityManager; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; @@ -42,9 +43,10 @@ class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged { private final MutableLiveData<Position> mPercentagePositionData = new MutableLiveData<>(); private final MenuInfoRepository mInfoRepository; - MenuViewModel(Context context, SecureSettings secureSettings) { - mInfoRepository = new MenuInfoRepository(context, /* settingsContentsChanged= */ this, - secureSettings); + MenuViewModel(Context context, AccessibilityManager accessibilityManager, + SecureSettings secureSettings) { + mInfoRepository = new MenuInfoRepository(context, + accessibilityManager, /* settingsContentsChanged= */ this, secureSettings); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java index ad12229fe4e7..56435df1ad2c 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java @@ -52,7 +52,6 @@ import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -472,8 +471,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, view.setContentDescription(item.getToolName()); icon.setImageDrawable(item.getToolIcon()); if (item.isCustomIcon()) { - icon.getDrawable().mutate().setTint(Utils.getColorAttr(context, - com.android.internal.R.attr.materialColorOnPrimaryContainer).getDefaultColor()); + icon.getDrawable().mutate().setTint(context.getColor( + com.android.internal.R.color.materialColorOnPrimaryContainer)); } text.setText(item.getToolName()); Intent intent = item.getToolIntent(); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java index e47e4b27d58a..7e1d538a80ee 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesListAdapter.java @@ -27,7 +27,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import com.android.settingslib.Utils; import com.android.systemui.bluetooth.qsdialog.DeviceItem; import com.android.systemui.res.R; @@ -131,10 +130,9 @@ public class HearingDevicesListAdapter extends RecyclerView.Adapter<RecyclerView } // tint different color in different state for bad color contrast problem - int tintColor = item.isActive() ? Utils.getColorAttr(mContext, - com.android.internal.R.attr.materialColorOnPrimaryContainer).getDefaultColor() - : Utils.getColorAttr(mContext, - com.android.internal.R.attr.materialColorOnSurface).getDefaultColor(); + int tintColor = item.isActive() ? mContext.getColor( + com.android.internal.R.color.materialColorOnPrimaryContainer) + : mContext.getColor(com.android.internal.R.color.materialColorOnSurface); Pair<Drawable, String> iconPair = item.getIconWithDescription(); if (iconPair != null) { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java index 28d742cfa49b..fda4f0385f55 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesSpinnerAdapter.java @@ -64,9 +64,9 @@ public class HearingDevicesSpinnerAdapter extends ArrayAdapter<String> { TextView text = view.findViewById(R.id.hearing_devices_spinner_text); if (text != null) { - int tintColor = Utils.getColorAttr(mContext, - isSelected ? com.android.internal.R.attr.materialColorOnPrimaryContainer - : com.android.internal.R.attr.materialColorOnSurface).getDefaultColor(); + int tintColor = mContext.getColor( + isSelected ? com.android.internal.R.color.materialColorOnPrimaryContainer + : com.android.internal.R.color.materialColorOnSurface); text.setTextColor(tintColor); } return view; diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java index d4e74d3bb906..9e1b09cf7891 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarView.java @@ -162,11 +162,12 @@ public class AmbientStatusBarView extends ConstraintLayout { void showIcon(@StatusIconType int iconType, boolean show, @Nullable String contentDescription) { View icon = mStatusIcons.get(iconType); - if (icon == null) { - return; - } + if (icon == null) return; + if (show && contentDescription != null) { icon.setContentDescription(contentDescription); + icon.setFocusable(true); + icon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } icon.setVisibility(show ? View.VISIBLE : View.GONE); mSystemStatusViewGroup.setVisibility(areAnyStatusIconsVisible() ? View.VISIBLE : View.GONE); @@ -174,9 +175,12 @@ public class AmbientStatusBarView extends ConstraintLayout { void setExtraStatusBarItemViews(List<View> views) { removeAllExtraStatusBarItemViews(); - views.forEach(view -> mExtraSystemStatusViewGroup.addView(view)); + views.forEach(view -> { + view.setFocusable(true); + view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + mExtraSystemStatusViewGroup.addView(view); + }); } - private View fetchStatusIconForResId(int resId) { final View statusIcon = findViewById(resId); return Objects.requireNonNull(statusIcon); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 316849d90cf3..d0cb507789a1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -714,12 +714,12 @@ public class AuthController implements onDialogDismissed(reason); } @Inject - public AuthController(Context context, + public AuthController(@Main Context context, @Application CoroutineScope applicationCoroutineScope, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, - @NonNull WindowManager windowManager, + @NonNull @Main WindowManager windowManager, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, Optional<AuthContextPlugins> contextPlugins, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index f6cc72431db0..22d2aaf2a8e7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -36,6 +36,7 @@ import com.android.systemui.Flags.lightRevealMigration import com.android.systemui.biometrics.data.repository.FacePropertyRepository import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.deviceentry.domain.interactor.AuthRippleInteractor import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.BiometricUnlockSource @@ -69,9 +70,9 @@ import javax.inject.Provider class AuthRippleController @Inject constructor( - private val sysuiContext: Context, + @Main private val sysuiContext: Context, private val authController: AuthController, - private val configurationController: ConfigurationController, + @Main private val configurationController: ConfigurationController, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, private val keyguardStateController: KeyguardStateController, private val wakefulnessLifecycle: WakefulnessLifecycle, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java index 027f6744d4d7..8376850c1a28 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.hardware.biometrics.BiometricSourceType; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import javax.inject.Inject; @@ -43,7 +44,7 @@ public class BiometricNotificationBroadcastReceiver extends BroadcastReceiver { private final BiometricNotificationDialogFactory mNotificationDialogFactory; @Inject BiometricNotificationBroadcastReceiver( - Context context, + @Main Context context, BiometricNotificationDialogFactory notificationDialogFactory) { mContext = context; mNotificationDialogFactory = notificationDialogFactory; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java index 3b49ce2f10f7..e5c22677dbcc 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java @@ -45,6 +45,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -145,7 +146,7 @@ public class BiometricNotificationService implements CoreStartable { }; @Inject - public BiometricNotificationService(@NonNull Context context, + public BiometricNotificationService(@NonNull @Main Context context, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, @NonNull KeyguardStateController keyguardStateController, @NonNull Handler handler, @NonNull NotificationManager notificationManager, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt index 178e1112fa6f..d9ed9ca1f07b 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt @@ -24,7 +24,7 @@ import com.android.systemui.biometrics.shared.model.SensorLocation import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.dagger.qualifiers.Main import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -43,7 +43,7 @@ constructor( @Application private val applicationScope: CoroutineScope, @Application private val context: Context, repository: FingerprintPropertyRepository, - @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, + @Main configurationInteractor: ConfigurationInteractor, displayStateInteractor: DisplayStateInteractor, udfpsOverlayInteractor: UdfpsOverlayInteractor, ) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt index c3dc2d406cbc..52e85576e756 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt @@ -26,6 +26,7 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.isDefaultOrientation import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState @@ -48,9 +49,9 @@ import kotlinx.coroutines.flow.onEach class SideFpsSensorInteractor @Inject constructor( - private val context: Context, + @Main private val context: Context, fingerprintPropertyRepository: FingerprintPropertyRepository, - windowManager: WindowManager, + @Main windowManager: WindowManager, displayStateInteractor: DisplayStateInteractor, fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>, biometricSettingsRepository: BiometricSettingsRepository, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt index 0ad83ec0c3f5..38b1d7d81332 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt @@ -37,7 +37,6 @@ import android.widget.Button import android.widget.LinearLayout import android.widget.Space import android.widget.TextView -import com.android.settingslib.Utils import com.android.systemui.biometrics.Utils.ellipsize import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R @@ -294,7 +293,7 @@ private fun getListItemBulletGapWidth(resources: Resources): Int = resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_list_item_bullet_gap_width) private fun getListItemBulletColor(context: Context): Int = - Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.materialColorOnSurface) + context.getColor(com.android.internal.R.color.materialColorOnSurface) private fun <T : View> T.width(function: (Int) -> Unit) { if (width == 0) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index df34952f4f8d..4dcf26808a9e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -982,8 +982,9 @@ private fun Context.getUserBadgedLogoInfo( activityTaskManager: ActivityTaskManager, ): Pair<Drawable?, String> { // If the app sets customized icon/description, use the passed-in value directly - var icon: Drawable? = - if (prompt.logoBitmap != null) BitmapDrawable(resources, prompt.logoBitmap) else null + val customizedIcon: Drawable? = + prompt.logoBitmap?.let { BitmapDrawable(resources, prompt.logoBitmap) } + var icon = customizedIcon var label = prompt.logoDescription ?: "" if (icon != null && label.isNotEmpty()) { return Pair(icon, label) @@ -1009,12 +1010,11 @@ private fun Context.getUserBadgedLogoInfo( } } - // Add user badge + // Add user badge for non-customized logo icon val userHandle = UserHandle.of(prompt.userInfo.userId) - if (label.isNotEmpty()) { - label = packageManager.getUserBadgedLabel(label, userHandle).toString() + if (icon != null && icon != customizedIcon) { + icon = packageManager.getUserBadgedIcon(icon, userHandle) } - icon = icon?.let { packageManager.getUserBadgedIcon(it, userHandle) } return Pair(icon, label) } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt index c2a4ee36dec6..555716191c96 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt @@ -164,21 +164,12 @@ constructor( showIndicatorForDeviceEntry: Boolean -> val callbacks = mutableListOf<LottieCallback>() if (showIndicatorForDeviceEntry) { - val indicatorColor = - com.android.settingslib.Utils.getColorAttrDefaultColor( - applicationContext, - com.android.internal.R.attr.materialColorPrimaryFixed - ) - val outerRimColor = - com.android.settingslib.Utils.getColorAttrDefaultColor( - applicationContext, - com.android.internal.R.attr.materialColorPrimaryFixedDim - ) - val chevronFill = - com.android.settingslib.Utils.getColorAttrDefaultColor( - applicationContext, - com.android.internal.R.attr.materialColorOnPrimaryFixed - ) + val indicatorColor = applicationContext.getColor( + com.android.internal.R.color.materialColorPrimaryFixed) + val outerRimColor = applicationContext.getColor( + com.android.internal.R.color.materialColorPrimaryFixedDim) + val chevronFill = applicationContext.getColor( + com.android.internal.R.color.materialColorOnPrimaryFixed) callbacks.add(LottieCallback(KeyPath(".blue600", "**"), indicatorColor)) callbacks.add(LottieCallback(KeyPath(".blue400", "**"), outerRimColor)) callbacks.add(LottieCallback(KeyPath(".black", "**"), chevronFill)) diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt index d7a0fc9770ee..9cfb5be478ed 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt @@ -405,13 +405,10 @@ internal constructor( } // updating icon colors - val tintColor = - com.android.settingslib.Utils.getColorAttr( - context, - if (item.isActive) InternalR.attr.materialColorOnPrimaryContainer - else InternalR.attr.materialColorOnSurface, - ) - .defaultColor + val tintColor = context.getColor( + if (item.isActive) InternalR.color.materialColorOnPrimaryContainer + else InternalR.color.materialColorOnSurface + ) // update icons iconView.apply { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt index a42ae03b2c4e..cdd1b3c3cf54 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt @@ -18,7 +18,6 @@ package com.android.systemui.bouncer.data.repository import android.content.res.Resources import com.android.internal.R -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -37,7 +36,7 @@ class EmergencyServicesRepository constructor( @Application private val applicationScope: CoroutineScope, @Main private val resources: Resources, - @GlobalConfig configurationRepository: ConfigurationRepository, + @Main configurationRepository: ConfigurationRepository, ) { /** * Whether to enable emergency services calls while the SIM card is locked. This is disabled in @@ -49,7 +48,7 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, - initialValue = getEnableEmergencyCallWhileSimLocked() + initialValue = getEnableEmergencyCallWhileSimLocked(), ) private fun getEnableEmergencyCallWhileSimLocked(): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt index 9f1781177f7a..a286d16826cd 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt @@ -33,13 +33,15 @@ object KeyguardBouncerConstants { const val DEFAULT_PIN_LENGTH = 6 object ColorId { - const val TITLE = com.android.internal.R.attr.materialColorOnSurface - const val PIN_SHAPES = com.android.internal.R.attr.materialColorOnSurfaceVariant - const val NUM_PAD_BACKGROUND = com.android.internal.R.attr.materialColorSurfaceContainerHigh - const val NUM_PAD_BACKGROUND_PRESSED = com.android.internal.R.attr.materialColorPrimaryFixed - const val NUM_PAD_PRESSED = com.android.internal.R.attr.materialColorOnPrimaryFixed - const val NUM_PAD_KEY = com.android.internal.R.attr.materialColorOnSurface - const val NUM_PAD_BUTTON = com.android.internal.R.attr.materialColorOnSecondaryFixed - const val EMERGENCY_BUTTON = com.android.internal.R.attr.materialColorTertiaryFixed + const val TITLE = com.android.internal.R.color.materialColorOnSurface + const val PIN_SHAPES = com.android.internal.R.color.materialColorOnSurfaceVariant + const val NUM_PAD_BACKGROUND = + com.android.internal.R.color.materialColorSurfaceContainerHigh + const val NUM_PAD_BACKGROUND_PRESSED = + com.android.internal.R.color.materialColorPrimaryFixed + const val NUM_PAD_PRESSED = com.android.internal.R.color.materialColorOnPrimaryFixed + const val NUM_PAD_KEY = com.android.internal.R.color.materialColorOnSurface + const val NUM_PAD_BUTTON = com.android.internal.R.color.materialColorOnSecondaryFixed + const val EMERGENCY_BUTTON = com.android.internal.R.color.materialColorTertiaryFixed } } 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/classifier/domain/interactor/FalsingInteractor.kt b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt index 074b64e0fab0..69f4f6d30f5d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt @@ -74,3 +74,12 @@ constructor( /** Returns `true` if the tap gesture should be rejected */ fun isFalseTap(@Penalty penalty: Int): Boolean = manager.isFalseTap(penalty) } + +inline fun FalsingInteractor.runIfNotFalseTap( + penalty: Int = FalsingManager.LOW_PENALTY, + action: () -> Unit, +) { + if (!isFalseTap(penalty)) { + action() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt index d235c95eb906..d53a737480a3 100644 --- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt +++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt @@ -18,6 +18,7 @@ package com.android.systemui.common.shared.model import android.annotation.AttrRes import android.annotation.ColorInt +import android.annotation.ColorRes /** * Models a color that can be either a specific [Color.Loaded] value or a resolvable theme @@ -28,4 +29,6 @@ sealed interface Color { data class Loaded(@ColorInt val color: Int) : Color data class Attribute(@AttrRes val attribute: Int) : Color + + data class Resource(@ColorRes val colorRes: Int) : Color } diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt index 0869351e727b..6a6c3eb05399 100644 --- a/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt +++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/TintedIcon.kt @@ -16,10 +16,10 @@ package com.android.systemui.common.shared.model -import androidx.annotation.AttrRes +import androidx.annotation.ColorRes /** Models an icon with a specific tint. */ data class TintedIcon( val icon: Icon, - @AttrRes val tint: Int?, + @ColorRes val tint: Int?, ) diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationModule.kt index 7f50e4a06022..ad504d502847 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationModule.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationModule.kt @@ -21,21 +21,11 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import dagger.Binds import dagger.Module import dagger.Provides -import javax.inject.Qualifier - -/** - * Annotates elements that provide information from the global configuration. - * - * The global configuration is the one associated with the main display. Secondary displays will - * apply override to the global configuration. Elements annotated with this shouldn't be used for - * secondary displays. - */ -@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class GlobalConfig @Module interface ConfigurationModule { @@ -45,32 +35,32 @@ interface ConfigurationModule { * now, without annotation the global config associated state is provided. */ @Binds - @Deprecated("Use the @GlobalConfig annotated one instead of this.") + @Deprecated("Use the @Main annotated one instead of this.") fun provideGlobalConfigurationState( - @GlobalConfig configurationState: ConfigurationState + @Main configurationState: ConfigurationState ): ConfigurationState @Binds - @Deprecated("Use the @GlobalConfig annotated one instead of this.") + @Deprecated("Use the @Main annotated one instead of this.") fun provideDefaultConfigurationState( - @GlobalConfig configurationState: ConfigurationInteractor + @Main configurationState: ConfigurationInteractor ): ConfigurationInteractor companion object { @SysUISingleton @Provides - @GlobalConfig + @Main fun provideGlobalConfigurationState( configStateFactory: ConfigurationStateImpl.Factory, configurationController: ConfigurationController, - @Application context: Context, + @Main context: Context, ): ConfigurationState { return configStateFactory.create(context, configurationController) } @SysUISingleton @Provides - @GlobalConfig + @Main fun provideGlobalConfigurationInteractor( configurationRepository: ConfigurationRepository ): ConfigurationInteractor { diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt index df891523798f..4d804d06fe87 100644 --- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt @@ -23,9 +23,9 @@ import android.view.DisplayInfo import androidx.annotation.DimenRes import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.wrapper.DisplayUtilsWrapper import dagger.Binds @@ -162,19 +162,19 @@ abstract class ConfigurationRepositoryModule { * injected. */ @Binds - @Deprecated("Use the ConfigurationRepository annotated with @GlobalConfig instead.") + @Deprecated("Use the ConfigurationRepository annotated with @Main instead.") @SysUISingleton abstract fun provideDefaultConfigRepository( - @GlobalConfig configurationRepository: ConfigurationRepository + @Main configurationRepository: ConfigurationRepository ): ConfigurationRepository companion object { @Provides - @GlobalConfig + @Main @SysUISingleton fun provideGlobalConfigRepository( context: Context, - @GlobalConfig configurationController: ConfigurationController, + @Main configurationController: ConfigurationController, factory: ConfigurationRepositoryImpl.Factory, ): ConfigurationRepository { return factory.create(context, configurationController) diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt index d648b9c6442b..5644e6b3b9bf 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt @@ -23,7 +23,6 @@ import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey import com.android.internal.logging.UiEventLogger import com.android.systemui.CoreStartable -import com.android.systemui.Flags.communalHubOnMobile import com.android.systemui.Flags.communalSceneKtfRefactor import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor @@ -218,7 +217,8 @@ constructor( newScene = CommunalScenes.Blank, loggingReason = "hub timeout", transitionKey = - if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade + if (communalSettingsInteractor.isV2FlagEnabled()) + CommunalTransitionKeys.SimpleFade else null, ) uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT) 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/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index 0cdbad40b2d1..862b05bc9b5d 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -63,24 +63,41 @@ constructor( .logDiffsForTable( tableLogBuffer = tableLogBuffer, columnPrefix = "disabledReason", - initialValue = CommunalEnabledState() + initialValue = CommunalEnabledState(), ) .map { model -> model.enabled } // Start this eagerly since the value is accessed synchronously in many places. .stateIn(scope = bgScope, started = SharingStarted.Eagerly, initialValue = false) /** - * Returns true if both the communal trunk-stable flag and resource flag are enabled. + * Returns true if any glanceable hub functionality should be enabled via configs and flags. * - * The trunk-stable flag is controlled by server rollout and is on all devices. The resource - * flag is enabled via resource overlay only on products we want the hub to be present on. + * This should be used for preventing basic glanceable hub functionality from running on devices + * that don't need it. * * If this is false, then the hub is definitely not available on the device. If this is true, * refer to [isCommunalEnabled] which takes into account other factors that can change at * runtime. + * + * If the glanceable_hub_v2 flag is enabled, checks the config_glanceableHubEnabled Android + * config boolean. Otherwise, checks the old config_communalServiceEnabled config and + * communal_hub flag. */ fun isCommunalFlagEnabled(): Boolean = repository.getFlagEnabled() + /** + * Returns true if the Android config config_glanceableHubEnabled and the glanceable_hub_v2 flag + * are enabled. + * + * This should be used to flag off new glanceable hub or dream behavior that should launch + * together with the new hub experience that brings the hub to mobile. + * + * The trunk-stable flag is controlled by server rollout and is on all devices. The Android + * config flag is enabled via resource overlay only on products we want the hub to be present + * on. + */ + fun isV2FlagEnabled(): Boolean = repository.getV2FlagEnabled() + /** The type of background to use for the hub. Used to experiment with different backgrounds */ val communalBackground: Flow<CommunalBackgroundType> = userInteractor.selectedUserInfo @@ -120,6 +137,6 @@ constructor( .stateIn( scope = bgScope, started = SharingStarted.WhileSubscribed(), - initialValue = null + initialValue = null, ) } 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/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 9cd6465266d4..eb7420f76f59 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -90,7 +90,7 @@ constructor( private val keyguardIndicationController: KeyguardIndicationController, communalSceneInteractor: CommunalSceneInteractor, private val communalInteractor: CommunalInteractor, - communalSettingsInteractor: CommunalSettingsInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, tutorialInteractor: CommunalTutorialInteractor, private val shadeInteractor: ShadeInteractor, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, @@ -372,6 +372,9 @@ constructor( val communalBackground: Flow<CommunalBackgroundType> = communalSettingsInteractor.communalBackground + /** See [CommunalSettingsInteractor.isV2FlagEnabled] */ + fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled() + companion object { const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L } diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/CommunalColors.kt b/packages/SystemUI/src/com/android/systemui/communal/util/CommunalColors.kt index 421774462974..481acc935f41 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/util/CommunalColors.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/util/CommunalColors.kt @@ -18,7 +18,6 @@ package com.android.systemui.communal.util import android.content.Context import android.graphics.Color -import com.android.settingslib.Utils import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -54,9 +53,6 @@ constructor( private fun loadBackgroundColor(): Color = Color.valueOf( - Utils.getColorAttrDefaultColor( - context, - com.android.internal.R.attr.materialColorPrimary - ) + context.getColor(com.android.internal.R.color.materialColorPrimary) ) } 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/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 78a8a42e2743..9ae106c3ab39 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -708,6 +708,14 @@ public class FrameworkServicesModule { return context.getSystemService(WindowManager.class); } + /** A window manager working for the default display only. */ + @Provides + @Singleton + @Main + static WindowManager provideMainWindowManager(WindowManager windowManager) { + return windowManager; + } + @Provides @Singleton static ViewCaptureAwareWindowManager provideViewCaptureAwareWindowManager( diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java index 3072f74dff2b..ddc88a839a63 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java @@ -21,6 +21,7 @@ import android.util.DisplayMetrics; import android.view.Display; import com.android.systemui.dagger.qualifiers.Application; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.PluginsModule; import com.android.systemui.unfold.UnfoldTransitionModule; import com.android.systemui.util.concurrency.GlobalConcurrencyModule; @@ -62,6 +63,13 @@ public class GlobalModule { return context.getApplicationContext(); } + /** Provides the default content with the main annotation. */ + @Provides + @Main + public Context provideMainContext(Context context) { + return context; + } + /** * @deprecated Deprecdated because {@link Display#getMetrics} is deprecated. */ diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java index 580896cb534e..00eead6eb7fc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -21,7 +21,7 @@ import com.android.systemui.CoreStartable; import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactoryBase; -import com.android.systemui.common.ui.GlobalConfig; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.PerUser; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; @@ -128,14 +128,14 @@ public interface SysUIComponent { * Creates a ConfigurationController. */ @SysUISingleton - @GlobalConfig + @Main ConfigurationController getConfigurationController(); /** * Creates a ConfigurationForwarder. */ @SysUISingleton - @GlobalConfig + @Main ConfigurationForwarder getConfigurationForwarder(); /** diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt index e76fd47c74de..c425bee74b2b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.kt @@ -25,7 +25,7 @@ import android.os.PatternMatcher import android.os.RemoteException import android.service.dreams.IDreamManager import android.util.Log -import com.android.systemui.Flags +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.dagger.qualifiers.SystemUser import com.android.systemui.dreams.dagger.DreamModule import com.android.systemui.log.LogBuffer @@ -48,6 +48,7 @@ constructor( @SystemUser monitor: Monitor, private val packageManager: PackageManager, private val dreamManager: IDreamManager, + private val communalSettingsInteractor: CommunalSettingsInteractor, @DreamLog private val logBuffer: LogBuffer, ) : ConditionalCoreStartable(monitor) { private var currentRegisteredState = false @@ -90,7 +91,7 @@ constructor( } if ( - Flags.communalHubOnMobile() && + communalSettingsInteractor.isV2FlagEnabled() && packageManager.getComponentEnabledSetting(overlayServiceComponent) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED ) { @@ -111,7 +112,7 @@ constructor( } // Enable for hub on mobile - if (Flags.communalHubOnMobile()) { + if (communalSettingsInteractor.isV2FlagEnabled()) { // Not available on TV or auto if ( packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) || diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index aee3a457e18a..571b37f43fd4 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -18,7 +18,6 @@ package com.android.systemui.dreams; import static android.service.dreams.Flags.dreamWakeRedirect; -import static com.android.systemui.Flags.communalHubOnMobile; import static com.android.systemui.Flags.glanceableHubAllowKeyguardWhenDreaming; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_WINDOW_TITLE; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_TOUCH_INSET_MANAGER; @@ -60,6 +59,7 @@ import com.android.systemui.ambient.touch.TouchMonitor; import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent; import com.android.systemui.ambient.touch.scrim.ScrimManager; import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor; import com.android.systemui.communal.shared.log.CommunalUiEvent; import com.android.systemui.communal.shared.model.CommunalScenes; import com.android.systemui.communal.shared.model.CommunalTransitionKeys; @@ -171,6 +171,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ private final SceneInteractor mSceneInteractor; private final CommunalInteractor mCommunalInteractor; + private final CommunalSettingsInteractor mCommunalSettingsInteractor; private boolean mCommunalAvailable; @@ -383,6 +384,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ KeyguardUpdateMonitor keyguardUpdateMonitor, ScrimManager scrimManager, CommunalInteractor communalInteractor, + CommunalSettingsInteractor communalSettingsInteractor, SceneInteractor sceneInteractor, SystemDialogsCloser systemDialogsCloser, UiEventLogger uiEventLogger, @@ -411,6 +413,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mDreamOverlayCallbackController = dreamOverlayCallbackController; mWindowTitle = windowTitle; mCommunalInteractor = communalInteractor; + mCommunalSettingsInteractor = communalSettingsInteractor; mSceneInteractor = sceneInteractor; mSystemDialogsCloser = systemDialogsCloser; mGestureInteractor = gestureInteractor; @@ -488,7 +491,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ final ArrayList<TouchHandler> touchHandlers = new ArrayList<>( List.of(dreamComplicationComponent.getHideComplicationTouchHandler())); - if (!communalHubOnMobile()) { + if (!mCommunalSettingsInteractor.isV2FlagEnabled()) { // Do not add the communal touch handler for glanceable hub v2 since there is no dream // to hub swipe gesture. touchHandlers.add(dreamOverlayComponent.getCommunalTouchHandler()); @@ -575,7 +578,8 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ } else { mCommunalInteractor.changeScene(CommunalScenes.Communal, "dream wake requested", - communalHubOnMobile() ? CommunalTransitionKeys.INSTANCE.getSimpleFade() : null); + mCommunalSettingsInteractor.isV2FlagEnabled() + ? CommunalTransitionKeys.INSTANCE.getSimpleFade() : null); } } 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/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt index 1e9be09bc3f3..246f6571f2da 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt @@ -17,7 +17,6 @@ package com.android.systemui.keyboard.backlight.ui.view -import android.annotation.AttrRes import android.annotation.ColorInt import android.app.Dialog import android.content.Context @@ -38,7 +37,6 @@ import android.widget.LinearLayout.LayoutParams import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT import androidx.annotation.IdRes import androidx.core.view.setPadding -import com.android.settingslib.Utils import com.android.systemui.res.R class KeyboardBacklightDialog( @@ -80,25 +78,25 @@ class KeyboardBacklightDialog( @ColorInt private val filledRectangleColor = - getColorFromStyle(com.android.internal.R.attr.materialColorPrimary) + context.getColor(com.android.internal.R.color.materialColorPrimary) @ColorInt private val emptyRectangleColor = - getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant) + context.getColor(com.android.internal.R.color.materialColorOutlineVariant) @ColorInt private val backgroundColor = - getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright) + context.getColor(com.android.internal.R.color.materialColorSurfaceBright) @ColorInt private val defaultIconColor = - getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary) + context.getColor(com.android.internal.R.color.materialColorOnPrimary) @ColorInt private val defaultIconBackgroundColor = - getColorFromStyle(com.android.internal.R.attr.materialColorPrimary) + context.getColor(com.android.internal.R.color.materialColorPrimary) @ColorInt private val dimmedIconColor = - getColorFromStyle(com.android.internal.R.attr.materialColorOnSurface) + context.getColor(com.android.internal.R.color.materialColorOnSurface) @ColorInt private val dimmedIconBackgroundColor = - getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceDim) + context.getColor(com.android.internal.R.color.materialColorSurfaceDim) private val levelContentDescription = context.getString(R.string.keyboard_backlight_value) @@ -153,11 +151,6 @@ class KeyboardBacklightDialog( } } - @ColorInt - fun getColorFromStyle(@AttrRes colorId: Int): Int { - return Utils.getColorAttrDefaultColor(context, colorId) - } - fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) { if (maxLevel != max || forceRefresh) { maxLevel = max diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt index 84a423e226b4..c3e6f0c6b280 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt @@ -21,11 +21,10 @@ import android.view.Surface import android.view.WindowManager import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.Utils -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyboard.docking.domain.interactor.KeyboardDockingIndicationInteractor import com.android.systemui.surfaceeffects.glowboxeffect.GlowBoxConfig import javax.inject.Inject @@ -37,10 +36,10 @@ import kotlinx.coroutines.flow.asStateFlow class KeyboardDockingIndicationViewModel @Inject constructor( - private val windowManager: WindowManager, - @Application private val context: Context, + @Main private val windowManager: WindowManager, + @Main private val context: Context, keyboardDockingIndicationInteractor: KeyboardDockingIndicationInteractor, - @GlobalConfig configurationInteractor: ConfigurationInteractor, + @Main configurationInteractor: ConfigurationInteractor, @Background private val backgroundScope: CoroutineScope, ) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/OWNERS b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/OWNERS new file mode 100644 index 000000000000..2355c48158f7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 1562219 +chrisgollner@google.com +jmokut@google.com
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/model/InternalShortcutModels.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/model/InternalShortcutModels.kt index 8c393e27da59..3020e5dedd17 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/model/InternalShortcutModels.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/model/InternalShortcutModels.kt @@ -21,6 +21,7 @@ import android.hardware.input.InputGestureData import android.view.KeyboardShortcutGroup import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesUtils import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType /** * Internal Keyboard Shortcut models to use with [ShortcutCategoriesUtils.fetchShortcutCategory] @@ -55,3 +56,8 @@ data class InternalKeyboardShortcutInfo( val icon: Icon? = null, val isCustomShortcut: Boolean = false, ) + +data class InternalGroupsSource( + val groups: List<InternalKeyboardShortcutGroup>, + val type: ShortcutCategoryType, +)
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt index 4af378646db3..8afec04a621c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/CustomShortcutCategoriesRepository.kt @@ -16,10 +16,8 @@ package com.android.systemui.keyboard.shortcut.data.repository -import android.content.Context import android.hardware.input.InputGestureData import android.hardware.input.InputGestureData.Builder -import android.hardware.input.InputGestureData.KeyTrigger import android.hardware.input.InputGestureData.createKeyTrigger import android.hardware.input.InputManager import android.hardware.input.KeyGestureEvent.KeyGestureType @@ -30,11 +28,8 @@ import com.android.systemui.Flags.shortcutHelperKeyGlyph import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult -import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup -import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey @@ -57,8 +52,7 @@ constructor( @Background private val backgroundScope: CoroutineScope, @Background private val bgCoroutineContext: CoroutineContext, private val shortcutCategoriesUtils: ShortcutCategoriesUtils, - private val context: Context, - private val inputGestureMaps: InputGestureMaps, + private val inputGestureDataAdapter: InputGestureDataAdapter, private val customInputGesturesRepository: CustomInputGesturesRepository, private val inputManager: InputManager ) : ShortcutCategoriesRepository { @@ -116,7 +110,7 @@ constructor( if (inputDevice == null) { emptyList() } else { - val sources = toInternalGroupSources(inputGestures) + val sources = inputGestureDataAdapter.toInternalGroupSources(inputGestures) val supportedKeyCodes = shortcutCategoriesUtils.fetchSupportedKeyCodes( inputDevice.id, @@ -216,7 +210,8 @@ constructor( return null } - return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label] + return inputGestureDataAdapter + .getKeyGestureTypeFromShortcutLabel(shortcutBeingCustomized.label) } @KeyGestureType @@ -232,7 +227,8 @@ constructor( return null } - return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[shortcutBeingCustomized.label] + return inputGestureDataAdapter + .getKeyGestureTypeFromShortcutLabel(shortcutBeingCustomized.label) } private fun Builder.addTriggerFromSelectedKeyCombination(): Builder { @@ -261,70 +257,6 @@ constructor( return _shortcutBeingCustomized.value } - private fun toInternalGroupSources( - inputGestures: List<InputGestureData> - ): List<InternalGroupsSource> { - val ungroupedInternalGroupSources = - inputGestures.mapNotNull { gestureData -> - val keyTrigger = gestureData.trigger as KeyTrigger - val keyGestureType = gestureData.action.keyGestureType() - fetchGroupLabelByGestureType(keyGestureType)?.let { groupLabel -> - toInternalKeyboardShortcutInfo(keyGestureType, keyTrigger)?.let { - internalKeyboardShortcutInfo -> - val group = - InternalKeyboardShortcutGroup( - label = groupLabel, - items = listOf(internalKeyboardShortcutInfo), - ) - - fetchShortcutCategoryTypeByGestureType(keyGestureType)?.let { - InternalGroupsSource(groups = listOf(group), type = it) - } - } - } - } - - return ungroupedInternalGroupSources - } - - private fun toInternalKeyboardShortcutInfo( - keyGestureType: Int, - keyTrigger: KeyTrigger, - ): InternalKeyboardShortcutInfo? { - fetchShortcutInfoLabelByGestureType(keyGestureType)?.let { - return InternalKeyboardShortcutInfo( - label = it, - keycode = keyTrigger.keycode, - modifiers = keyTrigger.modifierState, - isCustomShortcut = true, - ) - } - return null - } - - private fun fetchGroupLabelByGestureType(@KeyGestureType keyGestureType: Int): String? { - inputGestureMaps.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let { - return context.getString(it) - } ?: return null - } - - private fun fetchShortcutInfoLabelByGestureType(@KeyGestureType keyGestureType: Int): String? { - inputGestureMaps.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let { - return context.getString(it) - } ?: return null - } - - private fun fetchShortcutCategoryTypeByGestureType( - @KeyGestureType keyGestureType: Int - ): ShortcutCategoryType? { - return inputGestureMaps.gestureToShortcutCategoryTypeMap[keyGestureType] - } - - private data class InternalGroupsSource( - val groups: List<InternalKeyboardShortcutGroup>, - val type: ShortcutCategoryType, - ) - private companion object { private const val TAG = "CustomShortcutCategoriesRepository" } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapter.kt new file mode 100644 index 000000000000..df7101e21cce --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureDataAdapter.kt @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.data.repository + +import android.annotation.SuppressLint +import android.app.role.RoleManager +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.Intent.ACTION_MAIN +import android.content.Intent.CATEGORY_LAUNCHER +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager.MATCH_DEFAULT_ONLY +import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE +import android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE +import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES +import android.content.pm.PackageManager.NameNotFoundException +import android.graphics.drawable.Icon +import android.hardware.input.AppLaunchData +import android.hardware.input.AppLaunchData.CategoryData +import android.hardware.input.AppLaunchData.ComponentData +import android.hardware.input.AppLaunchData.RoleData +import android.hardware.input.InputGestureData +import android.hardware.input.InputGestureData.KeyTrigger +import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION +import android.hardware.input.KeyGestureEvent.KeyGestureType +import android.util.Log +import com.android.internal.app.ResolverActivity +import com.android.systemui.keyboard.shortcut.data.model.InternalGroupsSource +import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutGroup +import com.android.systemui.keyboard.shortcut.data.model.InternalKeyboardShortcutInfo +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType +import com.android.systemui.res.R +import com.android.systemui.settings.UserTracker +import javax.inject.Inject + + +class InputGestureDataAdapter +@Inject +constructor( + private val userTracker: UserTracker, + private val inputGestureMaps: InputGestureMaps, + private val context: Context +) { + private val userContext: Context + get() = userTracker.createCurrentUserContext(userTracker.userContext) + + fun toInternalGroupSources( + inputGestures: List<InputGestureData> + ): List<InternalGroupsSource> { + val ungroupedInternalGroupSources = + inputGestures.mapNotNull { gestureData -> + val keyTrigger = gestureData.trigger as KeyTrigger + val keyGestureType = gestureData.action.keyGestureType() + val appLaunchData: AppLaunchData? = gestureData.action.appLaunchData() + fetchGroupLabelByGestureType(keyGestureType)?.let { groupLabel -> + toInternalKeyboardShortcutInfo( + keyGestureType, + keyTrigger, + appLaunchData + )?.let { internalKeyboardShortcutInfo -> + val group = + InternalKeyboardShortcutGroup( + label = groupLabel, + items = listOf(internalKeyboardShortcutInfo), + ) + + fetchShortcutCategoryTypeByGestureType(keyGestureType)?.let { + InternalGroupsSource(groups = listOf(group), type = it) + } + } + } + } + + return ungroupedInternalGroupSources + } + + fun getKeyGestureTypeFromShortcutLabel(label: String): Int? { + return inputGestureMaps.shortcutLabelToKeyGestureTypeMap[label] + } + + private fun toInternalKeyboardShortcutInfo( + keyGestureType: Int, + keyTrigger: KeyTrigger, + appLaunchData: AppLaunchData?, + ): InternalKeyboardShortcutInfo? { + fetchShortcutLabelByGestureType(keyGestureType, appLaunchData)?.let { + return InternalKeyboardShortcutInfo( + label = it, + keycode = keyTrigger.keycode, + modifiers = keyTrigger.modifierState, + isCustomShortcut = true, + icon = appLaunchData?.let { fetchShortcutIconByAppLaunchData(appLaunchData) } + ) + } + return null + } + + @SuppressLint("QueryPermissionsNeeded") + private fun fetchShortcutIconByAppLaunchData( + appLaunchData: AppLaunchData + ): Icon? { + val intent = fetchIntentFromAppLaunchData(appLaunchData) ?: return null + val resolvedActivity = resolveSingleMatchingActivityFrom(intent) + + return if (resolvedActivity == null) { + null + } else { + Icon.createWithResource(context, resolvedActivity.iconResource) + } + } + + private fun fetchGroupLabelByGestureType(@KeyGestureType keyGestureType: Int): String? { + inputGestureMaps.gestureToInternalKeyboardShortcutGroupLabelResIdMap[keyGestureType]?.let { + return context.getString(it) + } ?: return null + } + + private fun fetchShortcutLabelByGestureType( + @KeyGestureType keyGestureType: Int, + appLaunchData: AppLaunchData? + ): String? { + inputGestureMaps.gestureToInternalKeyboardShortcutInfoLabelResIdMap[keyGestureType]?.let { + return context.getString(it) + } + + if (keyGestureType == KEY_GESTURE_TYPE_LAUNCH_APPLICATION) { + return fetchShortcutLabelByAppLaunchData(appLaunchData!!) + } + + return null + } + + private fun fetchShortcutLabelByAppLaunchData(appLaunchData: AppLaunchData): String? { + val intent = fetchIntentFromAppLaunchData(appLaunchData) ?: return null + val resolvedActivity = resolveSingleMatchingActivityFrom(intent) + + return if (resolvedActivity == null) { + getIntentCategoryLabel(intent.selector?.categories?.iterator()?.next()) + } else resolvedActivity.loadLabel(userContext.packageManager).toString() + + } + + @SuppressLint("QueryPermissionsNeeded") + private fun resolveSingleMatchingActivityFrom(intent: Intent): ActivityInfo? { + val packageManager = userContext.packageManager + val resolvedActivity = intent.resolveActivityInfo( + packageManager, + /* flags= */ MATCH_DEFAULT_ONLY + ) ?: return null + + val matchesMultipleActivities = + ResolverActivity::class.qualifiedName.equals(resolvedActivity.name) + + return if (matchesMultipleActivities) { + return null + } else resolvedActivity + } + + private fun getIntentCategoryLabel(category: String?): String? { + val categoryLabelRes = when (category.toString()) { + Intent.CATEGORY_APP_BROWSER -> R.string.keyboard_shortcut_group_applications_browser + Intent.CATEGORY_APP_CONTACTS -> R.string.keyboard_shortcut_group_applications_contacts + Intent.CATEGORY_APP_EMAIL -> R.string.keyboard_shortcut_group_applications_email + Intent.CATEGORY_APP_CALENDAR -> R.string.keyboard_shortcut_group_applications_calendar + Intent.CATEGORY_APP_MAPS -> R.string.keyboard_shortcut_group_applications_maps + Intent.CATEGORY_APP_MUSIC -> R.string.keyboard_shortcut_group_applications_music + Intent.CATEGORY_APP_MESSAGING -> R.string.keyboard_shortcut_group_applications_sms + Intent.CATEGORY_APP_CALCULATOR -> R.string.keyboard_shortcut_group_applications_calculator + else -> { + Log.w(TAG, ("No label for app category $category")) + null + } + } + + return if (categoryLabelRes == null){ + return null + } else { + context.getString(categoryLabelRes) + } + } + + private fun fetchIntentFromAppLaunchData(appLaunchData: AppLaunchData): Intent? { + return when (appLaunchData) { + is CategoryData -> Intent.makeMainSelectorActivity( + /* selectorAction= */ ACTION_MAIN, + /* selectorCategory= */ appLaunchData.category + ) + + is RoleData -> getRoleLaunchIntent(appLaunchData.role) + is ComponentData -> resolveComponentNameIntent( + packageName = appLaunchData.packageName, + className = appLaunchData.className + ) + + else -> null + } + } + + private fun resolveComponentNameIntent(packageName: String, className: String): Intent? { + buildIntentFromComponentName(ComponentName(packageName, className))?.let { return it } + buildIntentFromComponentName(ComponentName( + userContext.packageManager.canonicalToCurrentPackageNames(arrayOf(packageName))[0], + className + ))?.let { return it } + return null + } + + private fun buildIntentFromComponentName(componentName: ComponentName): Intent? { + try{ + val flags = + MATCH_DIRECT_BOOT_UNAWARE or MATCH_DIRECT_BOOT_AWARE or MATCH_UNINSTALLED_PACKAGES + // attempt to retrieve activity info to see if a NameNotFoundException is thrown. + userContext.packageManager.getActivityInfo(componentName, flags) + } catch (e: NameNotFoundException) { + Log.w( + TAG, + "Unable to find activity info for componentName: $componentName" + ) + return null + } + + return Intent(ACTION_MAIN).apply { + addCategory(CATEGORY_LAUNCHER) + component = componentName + } + } + + @SuppressLint("NonInjectedService") + private fun getRoleLaunchIntent(role: String): Intent? { + val packageManager = userContext.packageManager + val roleManager = userContext.getSystemService(RoleManager::class.java)!! + if (roleManager.isRoleAvailable(role)) { + roleManager.getDefaultApplication(role)?.let { rolePackage -> + packageManager.getLaunchIntentForPackage(rolePackage)?.let { return it } + ?: Log.w(TAG, "No launch intent for role $role") + } ?: Log.w(TAG, "No default application for role $role, user= ${userContext.user}") + } else { + Log.w(TAG, "Role $role is not available.") + } + return null + } + + private fun fetchShortcutCategoryTypeByGestureType( + @KeyGestureType keyGestureType: Int + ): ShortcutCategoryType? { + return inputGestureMaps.gestureToShortcutCategoryTypeMap[keyGestureType] + } + + private companion object { + private const val TAG = "InputGestureDataUtils" + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt index 1c380c26c6c3..d7be5e622276 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt @@ -22,14 +22,8 @@ import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_BACK import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_HOME +import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN @@ -74,13 +68,7 @@ class InputGestureMaps @Inject constructor(private val context: Context) { KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to MultiTasking, // App Category - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to AppCategories, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to AppCategories, + KEY_GESTURE_TYPE_LAUNCH_APPLICATION to AppCategories, ) val gestureToInternalKeyboardShortcutGroupLabelResIdMap = @@ -116,20 +104,14 @@ class InputGestureMaps @Inject constructor(private val context: Context) { R.string.shortcutHelper_category_split_screen, // App Category - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to - R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to - R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to - R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to - R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to R.string.keyboard_shortcut_group_applications, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to + KEY_GESTURE_TYPE_LAUNCH_APPLICATION to R.string.keyboard_shortcut_group_applications, ) + /** + * App Category shortcut labels are mapped dynamically based on intent + * see [InputGestureDataAdapter.fetchShortcutLabelByAppLaunchData] + */ val gestureToInternalKeyboardShortcutInfoLabelResIdMap = mapOf( // System Category @@ -154,26 +136,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) { KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_LEFT to R.string.system_multitasking_lhs, KEY_GESTURE_TYPE_SPLIT_SCREEN_NAVIGATION_RIGHT to R.string.system_multitasking_rhs, KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION to R.string.system_multitasking_full_screen, - KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_LEFT to - R.string.system_multitasking_splitscreen_focus_lhs, - KEY_GESTURE_TYPE_CHANGE_SPLITSCREEN_FOCUS_RIGHT to - R.string.system_multitasking_splitscreen_focus_rhs, - - // App Category - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALCULATOR to - R.string.keyboard_shortcut_group_applications_calculator, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR to - R.string.keyboard_shortcut_group_applications_calendar, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER to - R.string.keyboard_shortcut_group_applications_browser, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS to - R.string.keyboard_shortcut_group_applications_contacts, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL to - R.string.keyboard_shortcut_group_applications_email, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS to - R.string.keyboard_shortcut_group_applications_maps, - KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING to - R.string.keyboard_shortcut_group_applications_sms, ) val shortcutLabelToKeyGestureTypeMap: Map<String, Int> diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt index df6b04e2afd3..d785b5b5a7e7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt @@ -26,7 +26,6 @@ import android.view.KeyEvent.KEYCODE_EQUALS import android.view.KeyEvent.KEYCODE_LEFT_BRACKET import android.view.KeyEvent.KEYCODE_MINUS import android.view.KeyEvent.KEYCODE_RIGHT_BRACKET -import android.view.KeyEvent.META_ALT_ON import android.view.KeyEvent.META_CTRL_ON import android.view.KeyEvent.META_META_ON import android.view.KeyboardShortcutGroup @@ -74,20 +73,6 @@ constructor(@Main private val resources: Resources, @Application private val con command(META_META_ON or META_CTRL_ON, KEYCODE_DPAD_UP) } ) - // Change split screen focus to RHS: - // - Meta + Alt + Right arrow - add( - shortcutInfo(resources.getString(R.string.system_multitasking_splitscreen_focus_rhs)) { - command(META_META_ON or META_ALT_ON, KEYCODE_DPAD_RIGHT) - } - ) - // Change split screen focus to LHS: - // - Meta + Alt + Left arrow - add( - shortcutInfo(resources.getString(R.string.system_multitasking_splitscreen_focus_lhs)) { - command(META_META_ON or META_ALT_ON, KEYCODE_DPAD_LEFT) - } - ) if (enableMoveToNextDisplayShortcut()) { // Move a window to the next display: // - Meta + Ctrl + D diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index 7d9e010e31fa..af6f0cb2ec83 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -115,6 +115,7 @@ import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachIndexed import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.painter.rememberDrawablePainter +import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo @@ -126,7 +127,6 @@ import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState import com.android.systemui.res.R import kotlinx.coroutines.delay -import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel @Composable fun ShortcutHelper( @@ -189,7 +189,7 @@ private fun ActiveShortcutHelper( onKeyboardSettingsClicked, shortcutsUiState.isShortcutCustomizerFlagEnabled, onCustomizationRequested, - shortcutsUiState.shouldShowResetButton + shortcutsUiState.shouldShowResetButton, ) } } @@ -380,7 +380,7 @@ private fun ShortcutHelperTwoPane( onKeyboardSettingsClicked: () -> Unit, isShortcutCustomizerFlagEnabled: Boolean, onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {}, - shouldShowResetButton: Boolean + shouldShowResetButton: Boolean, ) { val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType } var isCustomizing by remember { mutableStateOf(false) } @@ -615,7 +615,7 @@ private fun Shortcut( } .focusable(interactionSource = interactionSource) .padding(8.dp) - .semantics { contentDescription = shortcut.contentDescription } + .semantics(mergeDescendants = true) { contentDescription = shortcut.contentDescription } ) { Row( modifier = @@ -801,7 +801,10 @@ private fun ShortcutKeyContainer(shortcutKeyContent: @Composable BoxScope.() -> private fun BoxScope.ShortcutTextKey(key: ShortcutKey.Text) { Text( text = key.value, - modifier = Modifier.align(Alignment.Center).padding(horizontal = 12.dp), + modifier = + Modifier.align(Alignment.Center).padding(horizontal = 12.dp).semantics { + hideFromAccessibility() + }, style = MaterialTheme.typography.titleSmall, ) } @@ -825,7 +828,7 @@ private fun FlowRowScope.ShortcutOrSeparator(spacing: Dp) { Spacer(Modifier.width(spacing)) Text( text = stringResource(R.string.shortcut_helper_key_combinations_or_separator), - modifier = Modifier.align(Alignment.CenterVertically), + modifier = Modifier.align(Alignment.CenterVertically).semantics { hideFromAccessibility() }, style = MaterialTheme.typography.titleSmall, ) Spacer(Modifier.width(spacing)) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt index 71f29c0062bc..d335a1806a6d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt @@ -20,12 +20,12 @@ import android.content.Context import android.content.Intent import android.provider.Settings import android.util.Log -import com.android.systemui.Flags.glanceableHubShortcutButton import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.communal.data.repository.CommunalSceneRepository import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalTransitionKeys import com.android.systemui.dagger.SysUISingleton @@ -46,6 +46,7 @@ constructor( @Application private val context: Context, private val communalSceneRepository: CommunalSceneRepository, private val communalInteractor: CommunalInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, private val sceneInteractor: SceneInteractor, ) : KeyguardQuickAffordanceConfig { @@ -61,8 +62,7 @@ constructor( override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> get() = flow { emit( - // TODO(b/378113263): Gate on getV2FlagEnabled() when ready. - if (!glanceableHubShortcutButton()) { + if (!communalSettingsInteractor.isV2FlagEnabled()) { Log.i(TAG, "Button hidden on lockscreen: flag not enabled.") KeyguardQuickAffordanceConfig.LockScreenState.Hidden } else if (!communalInteractor.isCommunalEnabled.value) { @@ -81,8 +81,7 @@ constructor( } override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState { - // TODO(b/378113263): Gate on getV2FlagEnabled() when ready. - return if (!glanceableHubShortcutButton()) { + return if (!communalSettingsInteractor.isV2FlagEnabled()) { Log.i(TAG, "Button unavailable in picker: flag not enabled.") KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice } else if (!communalInteractor.isCommunalEnabled.value) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 25e6f0e6044a..a9992112f893 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -21,7 +21,6 @@ import android.annotation.SuppressLint import android.app.DreamManager import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.systemui.Flags.communalHubOnMobile import com.android.systemui.Flags.communalSceneKtfRefactor import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor @@ -177,7 +176,8 @@ constructor( newScene = CommunalScenes.Communal, loggingReason = "FromDreamingTransitionInteractor", transitionKey = - if (communalHubOnMobile()) CommunalTransitionKeys.SimpleFade + if (communalSettingsInteractor.isV2FlagEnabled()) + CommunalTransitionKeys.SimpleFade else null, ) } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index 0cb8dd4798fa..5c03d65e570f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -36,7 +36,6 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull /** @@ -51,17 +50,11 @@ constructor( private val logger: KeyguardTransitionAnimationLogger, ) { /** Invoke once per transition between FROM->TO states to get access to a shared flow. */ - fun setup( - duration: Duration, - edge: Edge, - ): FlowBuilder { + fun setup(duration: Duration, edge: Edge): FlowBuilder { return FlowBuilder(duration, edge) } - inner class FlowBuilder( - private val transitionDuration: Duration, - private val edge: Edge, - ) { + inner class FlowBuilder(private val transitionDuration: Duration, private val edge: Edge) { fun setupWithoutSceneContainer(edge: Edge.StateToState): FlowBuilder { if (SceneContainerFlag.isEnabled) return this return setup(this.transitionDuration, edge) @@ -72,6 +65,8 @@ constructor( * in the range of [0, 1]. View animations should begin and end within a subset of this * range. This function maps the [startTime] and [duration] into [0, 1], when this subset is * valid. + * + * Note that [onCancel] isn't used when the scene framework is enabled. */ fun sharedFlow( duration: Duration, @@ -81,7 +76,7 @@ constructor( onCancel: (() -> Float)? = null, onFinish: (() -> Float)? = null, interpolator: Interpolator = LINEAR, - name: String? = null + name: String? = null, ): Flow<Float> { return sharedFlowWithState( duration = duration, @@ -113,7 +108,7 @@ constructor( onCancel: (() -> Float)? = null, onFinish: (() -> Float)? = null, interpolator: Interpolator = LINEAR, - name: String? = null + name: String? = null, ): Flow<StateToValue> { if (!duration.isPositive()) { throw IllegalArgumentException("duration must be a positive number: $duration") @@ -155,20 +150,40 @@ constructor( return transitionInteractor .transition(edge) - .map { step -> - StateToValue( - from = step.from, - to = step.to, - transitionState = step.transitionState, - value = - when (step.transitionState) { - STARTED -> stepToValue(step) - RUNNING -> stepToValue(step) - CANCELED -> onCancel?.invoke() - FINISHED -> onFinish?.invoke() - } - ) - .also { logger.logTransitionStep(name, step, it.value) } + .mapNotNull { step -> + if (SceneContainerFlag.isEnabled && step.transitionState == CANCELED) { + // When the scene framework is enabled, there's no need to emit an alpha + // value when the keyguard transition animation is canceled because there's + // always going to be a new, reversed keyguard transition animation back to + // the original KeyguardState that starts right when this one was canceled. + // + // For example, if swiping up slightly on the Lockscreen scene and then + // releasing before the transition to the Bouncer scene is committed, the + // KTF transition of LOCKSCREEN -> PRIMARY_BOUNCER received a CANCELED and + // the scene framework immediately starts a reversed transition of + // PRIMARY_BOUNCER -> LOCKSCREEN, which picks up where the previous one left + // off. + // + // If it were allowed for the CANCELED from the original KTF transition to + // emit a value, a race condition could form where the value from CANCELED + // arrives downstream _after_ the reversed transition is finished, causing + // the transition to end up in an incorrect state at rest. + null + } else { + StateToValue( + from = step.from, + to = step.to, + transitionState = step.transitionState, + value = + when (step.transitionState) { + STARTED -> stepToValue(step) + RUNNING -> stepToValue(step) + CANCELED -> onCancel?.invoke() + FINISHED -> onFinish?.invoke() + }, + ) + .also { logger.logTransitionStep(name, step, it.value) } + } } .distinctUntilChanged() } @@ -181,7 +196,7 @@ constructor( duration = 1.milliseconds, onStep = { value }, onCancel = { value }, - onFinish = { value } + onFinish = { value }, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index 3bdf7dac75b3..c59fe5357ccb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.binder import android.annotation.SuppressLint +import android.content.res.ColorStateList import android.graphics.Rect import android.graphics.drawable.Animatable2 import android.util.Size @@ -37,7 +38,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.settingslib.Utils import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.animation.view.LaunchableLinearLayout @@ -382,25 +382,25 @@ object KeyguardBottomAreaViewBinder { view.isActivated = viewModel.isActivated view.drawable.setTint( - Utils.getColorAttrDefaultColor( - view.context, + view.context.getColor( if (viewModel.isActivated) { - com.android.internal.R.attr.materialColorOnPrimaryFixed + com.android.internal.R.color.materialColorOnPrimaryFixed } else { - com.android.internal.R.attr.materialColorOnSurface - }, + com.android.internal.R.color.materialColorOnSurface + } ) ) view.backgroundTintList = if (!viewModel.isSelected) { - Utils.getColorAttr( - view.context, - if (viewModel.isActivated) { - com.android.internal.R.attr.materialColorPrimaryFixed - } else { - com.android.internal.R.attr.materialColorSurfaceContainerHigh - } + ColorStateList.valueOf( + view.context.getColor( + if (viewModel.isActivated) { + com.android.internal.R.color.materialColorPrimaryFixed + } else { + com.android.internal.R.color.materialColorSurfaceContainerHigh + } + ) ) } else { null diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt index 191e08b0de77..5c8a234ec6c4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.binder import android.annotation.SuppressLint +import android.content.res.ColorStateList import android.graphics.drawable.Animatable2 import android.util.Size import android.view.View @@ -32,7 +33,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.logging.KeyguardQuickAffordancesLogger -import com.android.settingslib.Utils import com.android.systemui.animation.Expandable import com.android.systemui.animation.view.LaunchableImageView import com.android.systemui.common.shared.model.Icon @@ -176,25 +176,25 @@ constructor( view.isActivated = viewModel.isActivated view.drawable.setTint( - Utils.getColorAttrDefaultColor( - view.context, + view.context.getColor( if (viewModel.isActivated) { - com.android.internal.R.attr.materialColorOnPrimaryFixed + com.android.internal.R.color.materialColorOnPrimaryFixed } else { - com.android.internal.R.attr.materialColorOnSurface + com.android.internal.R.color.materialColorOnSurface }, ) ) view.backgroundTintList = if (!viewModel.isSelected) { - Utils.getColorAttr( - view.context, - if (viewModel.isActivated) { - com.android.internal.R.attr.materialColorPrimaryFixed - } else { - com.android.internal.R.attr.materialColorSurfaceContainerHigh - } + ColorStateList.valueOf( + view.context.getColor( + if (viewModel.isActivated) { + com.android.internal.R.color.materialColorPrimaryFixed + } else { + com.android.internal.R.color.materialColorSurfaceContainerHigh + } + ) ) } else { null 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/controls/ui/viewmodel/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt index 2a9fe8314349..1e99697e6a33 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModel.kt @@ -93,7 +93,7 @@ constructor( scrubbing = false, elapsedTime = null, duration = 0, - listening = false + listening = false, ) set(value) { val enabledChanged = value.enabled != field.enabled @@ -135,7 +135,6 @@ constructor( override fun onMetadataChanged(metadata: MediaMetadata?) { if (!Flags.mediaControlsPostsOptimization()) return - val (enabled, duration) = getEnabledStateAndDuration(metadata) if (_data.duration != duration) { _data = _data.copy(enabled = enabled, duration = duration) @@ -323,7 +322,7 @@ constructor( bgExecutor.executeRepeatedly( this::checkPlaybackPosition, 0L, - POSITION_UPDATE_INTERVAL_MILLIS + POSITION_UPDATE_INTERVAL_MILLIS, ) cancel = Runnable { cancelPolling.run() @@ -331,6 +330,7 @@ constructor( } } } else { + checkPlaybackPosition() cancel?.run() cancel = null } @@ -542,7 +542,7 @@ constructor( eventStart: MotionEvent?, event: MotionEvent, distanceX: Float, - distanceY: Float + distanceY: Float, ): Boolean { return shouldGoToSeekBar } @@ -556,7 +556,7 @@ constructor( eventStart: MotionEvent?, event: MotionEvent, velocityX: Float, - velocityY: Float + velocityY: Float, ): Boolean { if (Math.abs(velocityX) > flingVelocity || Math.abs(velocityY) > flingVelocity) { viewModel.onSeekFalse() 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/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt index 2f0e1298499c..f8d317a7799f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt @@ -19,12 +19,12 @@ package com.android.systemui.media.taptotransfer.common import android.content.Context import android.content.pm.PackageManager import android.graphics.drawable.Drawable -import androidx.annotation.AttrRes +import androidx.annotation.ColorRes import androidx.annotation.DrawableRes -import com.android.systemui.res.R import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.TintedIcon +import com.android.systemui.res.R import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo.Companion.DEFAULT_ICON_TINT /** Utility methods for media tap-to-transfer. */ @@ -108,7 +108,7 @@ class MediaTttUtils { data class IconInfo( val contentDescription: ContentDescription, val icon: MediaTttIcon, - @AttrRes val tint: Int?, + @ColorRes val tint: Int?, /** * True if [drawable] is the app's icon, and false if [drawable] is some generic default icon. */ 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/navigationbar/gestural/BackPanel.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt index 2d001508a720..138ac8668a14 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt @@ -12,7 +12,6 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce import com.android.internal.util.LatencyTracker -import com.android.settingslib.Utils import com.android.systemui.navigationbar.gestural.BackPanelController.DelayedOnAnimationEndListener private const val TAG = "BackPanel" @@ -156,23 +155,21 @@ class BackPanel(context: Context, private val latencyTracker: LatencyTracker) : Configuration.UI_MODE_NIGHT_YES arrowPaint.color = - Utils.getColorAttrDefaultColor( - context, + context.getColor( if (isDeviceInNightTheme) { - com.android.internal.R.attr.materialColorOnSecondaryContainer + com.android.internal.R.color.materialColorOnSecondaryContainer } else { - com.android.internal.R.attr.materialColorOnSecondaryFixed - }, + com.android.internal.R.color.materialColorOnSecondaryFixed + } ) arrowBackgroundPaint.color = - Utils.getColorAttrDefaultColor( - context, + context.getColor( if (isDeviceInNightTheme) { - com.android.internal.R.attr.materialColorSecondaryContainer + com.android.internal.R.color.materialColorSecondaryContainer } else { - com.android.internal.R.attr.materialColorSecondaryFixedDim - }, + com.android.internal.R.color.materialColorSecondaryFixedDim + } ) } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt index b26ae6cdf0bd..f53b6cd29806 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogV2.kt @@ -40,8 +40,8 @@ import androidx.annotation.WorkerThread import androidx.core.view.ViewCompat import androidx.core.view.accessibility.AccessibilityNodeInfoCompat import com.android.settingslib.Utils -import com.android.systemui.res.R import com.android.systemui.animation.ViewHierarchyAnimator +import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.maybeForceFullscreen import java.lang.ref.WeakReference @@ -347,16 +347,16 @@ class PrivacyDialogV2( private fun getForegroundColor(active: Boolean) = Utils.getColorAttrDefaultColor( context, - if (active) com.android.internal.R.attr.materialColorOnPrimaryFixed - else com.android.internal.R.attr.materialColorOnSurface + if (active) com.android.internal.R.color.materialColorOnPrimaryFixed + else com.android.internal.R.color.materialColorOnSurface, ) @ColorInt private fun getBackgroundColor(active: Boolean) = Utils.getColorAttrDefaultColor( context, - if (active) com.android.internal.R.attr.materialColorPrimaryFixed - else com.android.internal.R.attr.materialColorSurfaceContainerHigh + if (active) com.android.internal.R.color.materialColorPrimaryFixed + else com.android.internal.R.color.materialColorSurfaceContainerHigh, ) private fun getMutableDrawable(@DrawableRes resId: Int) = context.getDrawable(resId)!!.mutate() diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java index ba3357c8b591..7c7f48e0d37b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java @@ -19,6 +19,8 @@ import android.content.Context; import android.content.res.Resources; import android.provider.Settings; +import androidx.annotation.NonNull; + import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.res.R; @@ -80,6 +82,12 @@ public interface QSHost { void addTile(ComponentName tile); /** + * Click on a tile. Used by external commands + * @param tile the component name of the {@link android.service.quicksettings.TileService} + */ + void clickTile(@NonNull ComponentName tile); + + /** * Adds a custom tile to the set of current tiles. * @param tile the component name of the {@link android.service.quicksettings.TileService} * @param end if true, the tile will be added at the end. If false, at the beginning. diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt index 0d464f5a0936..dc3b58247152 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/QSHostAdapter.kt @@ -19,11 +19,13 @@ package com.android.systemui.qs import android.content.ComponentName import android.content.Context import androidx.annotation.GuardedBy +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.external.TileServiceRequestController +import com.android.systemui.qs.flags.QsInCompose import com.android.systemui.qs.pipeline.data.repository.TileSpecRepository.Companion.POSITION_AT_END import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository @@ -32,7 +34,6 @@ import com.android.systemui.shade.ShadeDisplayAware import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import com.android.app.tracing.coroutines.launchTraced as launch /** * Adapter to determine what real class to use for classes that depend on [QSHost]. @@ -135,4 +136,12 @@ constructor( override fun indexOf(tileSpec: String): Int { return specs.indexOf(tileSpec) } + + override fun clickTile(tile: ComponentName) { + if (QsInCompose.isUnexpectedlyInLegacyMode()) { + return + } + val spec = TileSpec.create(tile) + interactor.currentTiles.value.firstOrNull { it.spec == spec }?.tile?.click(null) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 9dc21fb89b16..5b8ac6408077 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -33,7 +33,6 @@ import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner import androidx.annotation.VisibleForTesting import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -47,7 +46,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.verticalScroll @@ -247,51 +245,57 @@ constructor( private fun Content() { PlatformTheme(isDarkTheme = true) { ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) { - AnimatedVisibility( - visible = viewModel.isQsVisible, - modifier = - Modifier.graphicsLayer { alpha = viewModel.viewAlpha } - // Clipping before translation to match QSContainerImpl.onDraw - .offset { - IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt()) - } - .thenIf(notificationScrimClippingParams.isEnabled) { - Modifier.notificationScrimClip { - notificationScrimClippingParams.params + if (viewModel.isQsVisibleAndAnyShadeExpanded) { + Box( + modifier = + Modifier.graphicsLayer { alpha = viewModel.viewAlpha } + // Clipping before translation to match QSContainerImpl.onDraw + .offset { + IntOffset( + x = 0, + y = viewModel.viewTranslationY.fastRoundToInt(), + ) + } + .thenIf(notificationScrimClippingParams.isEnabled) { + Modifier.notificationScrimClip { + notificationScrimClippingParams.params + } } + // Disable touches in the whole composable while the mirror is + // showing. While the mirror is showing, an ancestor of the + // ComposeView is made alpha 0, but touches are still being captured + // by the composables. + .gesturesDisabled(viewModel.showingMirror) + ) { + val isEditing by + viewModel.containerViewModel.editModeViewModel.isEditing + .collectAsStateWithLifecycle() + val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS) + AnimatedContent( + targetState = isEditing, + transitionSpec = { + fadeIn(animationSpecEditMode) togetherWith + fadeOut(animationSpecEditMode) + }, + label = "EditModeAnimatedContent", + ) { editing -> + if (editing) { + val qqsPadding = viewModel.qqsHeaderHeight + EditMode( + viewModel = viewModel.containerViewModel.editModeViewModel, + modifier = + Modifier.fillMaxWidth() + .padding(top = { qqsPadding }) + .padding( + horizontal = { + QuickSettingsShade.Dimensions.Padding + .roundToPx() + } + ), + ) + } else { + CollapsableQuickSettingsSTL() } - // Disable touches in the whole composable while the mirror is showing. - // While the mirror is showing, an ancestor of the ComposeView is made - // alpha 0, but touches are still being captured by the composables. - .gesturesDisabled(viewModel.showingMirror), - ) { - val isEditing by - viewModel.containerViewModel.editModeViewModel.isEditing - .collectAsStateWithLifecycle() - val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS) - AnimatedContent( - targetState = isEditing, - transitionSpec = { - fadeIn(animationSpecEditMode) togetherWith - fadeOut(animationSpecEditMode) - }, - label = "EditModeAnimatedContent", - ) { editing -> - if (editing) { - val qqsPadding = viewModel.qqsHeaderHeight - EditMode( - viewModel = viewModel.containerViewModel.editModeViewModel, - modifier = - Modifier.fillMaxWidth() - .padding(top = { qqsPadding }) - .padding( - horizontal = { - QuickSettingsShade.Dimensions.Padding.roundToPx() - } - ), - ) - } else { - CollapsableQuickSettingsSTL() } } } @@ -326,9 +330,15 @@ constructor( } SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) { - scene(QuickSettings) { QuickSettingsElement() } + scene(QuickSettings) { + LaunchedEffect(Unit) { viewModel.onQSOpen() } + QuickSettingsElement() + } - scene(QuickQuickSettings) { QuickQuickSettingsElement() } + scene(QuickQuickSettings) { + LaunchedEffect(Unit) { viewModel.onQQSOpen() } + QuickQuickSettingsElement() + } } } @@ -709,12 +719,7 @@ constructor( GridAnchor() TileGrid( viewModel = containerViewModel.tileGridViewModel, - modifier = - Modifier.fillMaxWidth() - .heightIn( - max = - QuickSettingsShade.Dimensions.GridMaxHeight - ), + modifier = Modifier.fillMaxWidth(), ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt index 02498d69b83d..07ceb6425574 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt @@ -28,6 +28,7 @@ import androidx.compose.runtime.snapshotFlow import androidx.lifecycle.LifecycleCoroutineScope import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.internal.logging.UiEventLogger import com.android.keyguard.BouncerPanelExpansionCalculator import com.android.systemui.Dumpable import com.android.systemui.animation.ShadeInterpolation @@ -51,6 +52,7 @@ import com.android.systemui.media.dagger.MediaModule.QS_PANEL import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.FooterActionsController +import com.android.systemui.qs.QSEvent import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeLog import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel @@ -62,6 +64,7 @@ import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController @@ -101,6 +104,7 @@ constructor( DisableFlagsInteractor: DisableFlagsInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, private val largeScreenShadeInterpolator: LargeScreenShadeInterpolator, + private val shadeInteractor: ShadeInteractor, @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, private val largeScreenHeaderHelper: LargeScreenHeaderHelper, private val squishinessInteractor: TileSquishinessInteractor, @@ -111,6 +115,7 @@ constructor( @Named(QUICK_QS_PANEL) val qqsMediaHost: MediaHost, @Named(QS_PANEL) val qsMediaHost: MediaHost, @Named(QSFragmentComposeModule.QS_USING_MEDIA_PLAYER) private val usingMedia: Boolean, + private val uiEventLogger: UiEventLogger, @Assisted private val lifecycleScope: LifecycleCoroutineScope, ) : Dumpable, ExclusiveActivatable() { @@ -129,6 +134,9 @@ constructor( var isQsVisible by mutableStateOf(false) + val isQsVisibleAndAnyShadeExpanded: Boolean + get() = anyShadeExpanded && isQsVisible + // This can only be negative if undefined (in which case it will be -1f), else it will be // in [0, 1]. In some cases, it could be set back to -1f internally to indicate that it's // different to every value in [0, 1]. @@ -429,6 +437,12 @@ constructor( ), ) + private val anyShadeExpanded by + hydrator.hydratedStateOf( + traceName = "anyShadeExpanded", + source = shadeInteractor.isAnyExpanded, + ) + fun applyNewQsScrollerBounds(left: Float, top: Float, right: Float, bottom: Float) { if (usingMedia) { qsMediaHost.currentClipping.set( @@ -444,6 +458,14 @@ constructor( falsingInteractor.isFalseTouch(Classifier.QS_SWIPE_NESTED) } + fun onQQSOpen() { + uiEventLogger.log(QSEvent.QQS_PANEL_EXPANDED) + } + + fun onQSOpen() { + uiEventLogger.log(QSEvent.QS_PANEL_EXPANDED) + } + override suspend fun onActivated(): Nothing { initMediaHosts() // init regardless of using media (same as current QS). coroutineScope { @@ -503,6 +525,8 @@ constructor( printSection("Quick Settings state") { println("isQSExpanded", isQsExpanded) println("isQSVisible", isQsVisible) + println("anyShadeExpanded", anyShadeExpanded) + println("isQSVisibleAndAnyShadeExpanded", isQsVisibleAndAnyShadeExpanded) println("isQSEnabled", isQsEnabled) println("isCustomizing", containerViewModel.editModeViewModel.isEditing.value) println("inFirstPage", inFirstPage) 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/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index 8ef637545e69..cc872060b827 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -23,12 +23,12 @@ import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleOwner +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.Utils import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager @@ -38,6 +38,7 @@ import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig import com.android.systemui.res.R import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.util.icuMessageFormat import javax.inject.Inject import javax.inject.Named @@ -54,7 +55,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.isActive -import com.android.app.tracing.coroutines.launchTraced as launch private const val TAG = "FooterActionsViewModel" @@ -113,7 +113,7 @@ class FooterActionsViewModel( class Factory @Inject constructor( - @ShadeDisplayAware private val context: Context, + @ShadeDisplayAware private val context: Context, private val falsingManager: FalsingManager, private val footerActionsInteractor: FooterActionsInteractor, private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, @@ -211,7 +211,7 @@ fun FooterActionsViewModel( false /* if the dismiss should be deferred */ }, null /* cancelAction */, - true /* afterKeyguardGone */ + true, /* afterKeyguardGone */ ) } @@ -269,29 +269,7 @@ fun FooterActionsViewModel( .distinctUntilChanged() val userSwitcher = - footerActionsInteractor.userSwitcherStatus - .map { userSwitcherStatus -> - when (userSwitcherStatus) { - UserSwitcherStatusModel.Disabled -> null - is UserSwitcherStatusModel.Enabled -> { - if (userSwitcherStatus.currentUserImage == null) { - Log.e( - TAG, - "Skipped the addition of user switcher button because " + - "currentUserImage is missing", - ) - return@map null - } - - userSwitcherButtonViewModel( - qsThemedContext, - userSwitcherStatus, - ::onUserSwitcherClicked - ) - } - } - } - .distinctUntilChanged() + userSwitcherViewModel(qsThemedContext, footerActionsInteractor, ::onUserSwitcherClicked) val settings = settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked) val power = @@ -311,6 +289,36 @@ fun FooterActionsViewModel( ) } +fun userSwitcherViewModel( + themedContext: Context, + footerActionsInteractor: FooterActionsInteractor, + onUserSwitcherClicked: (Expandable) -> Unit, +): Flow<FooterActionsButtonViewModel?> { + return footerActionsInteractor.userSwitcherStatus + .map { userSwitcherStatus -> + when (userSwitcherStatus) { + UserSwitcherStatusModel.Disabled -> null + is UserSwitcherStatusModel.Enabled -> { + if (userSwitcherStatus.currentUserImage == null) { + Log.e( + TAG, + "Skipped the addition of user switcher button because " + + "currentUserImage is missing", + ) + return@map null + } + + userSwitcherButtonViewModel( + themedContext, + userSwitcherStatus, + onUserSwitcherClicked, + ) + } + } + } + .distinctUntilChanged() +} + fun securityButtonViewModel( config: SecurityButtonConfig, onSecurityButtonClicked: (Context, Expandable) -> Unit, @@ -369,7 +377,7 @@ fun userSwitcherButtonViewModel( private fun userSwitcherContentDescription( qsThemedContext: Context, - currentUser: String? + currentUser: String?, ): String? { return currentUser?.let { user -> qsThemedContext.getString(R.string.accessibility_quick_settings_user, user) @@ -384,13 +392,9 @@ fun settingsButtonViewModel( id = R.id.settings_button_container, Icon.Resource( R.drawable.ic_settings, - ContentDescription.Resource(R.string.accessibility_quick_settings_settings) + ContentDescription.Resource(R.string.accessibility_quick_settings_settings), ), - iconTint = - Utils.getColorAttrDefaultColor( - qsThemedContext, - R.attr.onShadeInactiveVariant, - ), + iconTint = Utils.getColorAttrDefaultColor(qsThemedContext, R.attr.onShadeInactiveVariant), backgroundColor = R.attr.shadeInactive, onSettingsButtonClicked, ) @@ -404,14 +408,14 @@ fun powerButtonViewModel( id = R.id.pm_lite, Icon.Resource( android.R.drawable.ic_lock_power_off, - ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu) + ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu), ), iconTint = Utils.getColorAttrDefaultColor( qsThemedContext, - R.attr.onShadeActive, + if (DualShade.isEnabled) R.attr.onShadeInactiveVariant else R.attr.onShadeActive, ), - backgroundColor = R.attr.shadeActive, + backgroundColor = if (DualShade.isEnabled) R.attr.shadeInactive else R.attr.shadeActive, onPowerButtonClicked, ) } 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/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt index 1f55ac777de5..f4bf53cafd19 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt @@ -21,8 +21,6 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.LogBufferFactory import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepositoryImpl -import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository -import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepositoryImpl import com.android.systemui.qs.panels.domain.interactor.EditTilesResetInteractor import com.android.systemui.qs.panels.domain.interactor.SizedTilesResetInteractor import com.android.systemui.qs.panels.shared.model.GridLayoutType @@ -49,9 +47,6 @@ interface PanelsModule { ): DefaultLargeTilesRepository @Binds - fun bindGridLayoutTypeRepository(impl: GridLayoutTypeRepositoryImpl): GridLayoutTypeRepository - - @Binds fun bindEditTilesResetInteractor(impl: SizedTilesResetInteractor): EditTilesResetInteractor @Binds fun bindIconTilesViewModel(impl: IconTilesViewModelImpl): IconTilesViewModel diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt index 47c4ffd6a2cc..f17abe888b2e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt @@ -17,28 +17,14 @@ package com.android.systemui.qs.panels.data.repository import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.qs.panels.shared.model.GridLayoutType +import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType import javax.inject.Inject -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow - -interface GridLayoutTypeRepository { - val layout: StateFlow<GridLayoutType> - - fun setLayout(type: GridLayoutType) -} +import kotlinx.coroutines.flow.flowOf @SysUISingleton -class GridLayoutTypeRepositoryImpl @Inject constructor() : GridLayoutTypeRepository { - private val _layout: MutableStateFlow<GridLayoutType> = - MutableStateFlow(PaginatedGridLayoutType) - override val layout = _layout.asStateFlow() +class GridLayoutTypeRepository @Inject constructor() { + val defaultLayoutType = flowOf(PaginatedGridLayoutType) - override fun setLayout(type: GridLayoutType) { - if (_layout.value != type) { - _layout.value = type - } - } + val dualShadeLayoutType = flowOf(InfiniteGridLayoutType) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractor.kt index 4af1b2223c4c..e493cbeebae8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractor.kt @@ -19,14 +19,23 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository import com.android.systemui.qs.panels.shared.model.GridLayoutType +import com.android.systemui.shade.domain.interactor.ShadeModeInteractor +import com.android.systemui.shade.shared.model.ShadeMode import javax.inject.Inject -import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest @SysUISingleton -class GridLayoutTypeInteractor @Inject constructor(private val repo: GridLayoutTypeRepository) { - val layout: StateFlow<GridLayoutType> = repo.layout - - fun setLayoutType(type: GridLayoutType) { - repo.setLayout(type) - } +@OptIn(ExperimentalCoroutinesApi::class) +class GridLayoutTypeInteractor +@Inject +constructor(private val repo: GridLayoutTypeRepository, shadeModeInteractor: ShadeModeInteractor) { + val layout: Flow<GridLayoutType> = + shadeModeInteractor.shadeMode.flatMapLatest { shadeMode -> + when (shadeMode) { + is ShadeMode.Dual -> repo.dualShadeLayoutType + else -> repo.defaultLayoutType + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt index 35faa97db2fe..405ce8a8e5e0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt @@ -44,19 +44,28 @@ import com.android.systemui.qs.pipeline.shared.TileSpec /** Holds the [TileSpec] of the tile being moved and receives drag and drop events. */ interface DragAndDropState { val draggedCell: SizedTile<EditTileViewModel>? + val draggedPosition: Offset val dragInProgress: Boolean + val dragType: DragType? fun isMoving(tileSpec: TileSpec): Boolean - fun onStarted(cell: SizedTile<EditTileViewModel>) + fun onStarted(cell: SizedTile<EditTileViewModel>, dragType: DragType) - fun onMoved(target: Int, insertAfter: Boolean) + fun onTargeting(target: Int, insertAfter: Boolean) + + fun onMoved(offset: Offset) fun movedOutOfBounds() fun onDrop() } +enum class DragType { + Add, + Move, +} + /** * Registers a composable as a [DragAndDropTarget] to receive drop events. Use this outside the tile * grid to catch out of bounds drops. @@ -72,6 +81,10 @@ fun Modifier.dragAndDropRemoveZone( val target = remember(dragAndDropState) { object : DragAndDropTarget { + override fun onMoved(event: DragAndDropEvent) { + dragAndDropState.onMoved(event.toOffset()) + } + override fun onDrop(event: DragAndDropEvent): Boolean { return dragAndDropState.draggedCell?.let { onDrop(it.tile.tileSpec) @@ -117,8 +130,11 @@ fun Modifier.dragAndDropTileList( } override fun onMoved(event: DragAndDropEvent) { + val offset = event.toOffset() + dragAndDropState.onMoved(offset) + // Drag offset relative to the list's top left corner - val relativeDragOffset = event.dragOffsetRelativeTo(contentOffset()) + val relativeDragOffset = offset - contentOffset() val targetItem = gridState.layoutInfo.visibleItemsInfo.firstOrNull { item -> // Check if the drag is on this item @@ -126,7 +142,7 @@ fun Modifier.dragAndDropTileList( } targetItem?.let { - dragAndDropState.onMoved(it.index, insertAfter(it, relativeDragOffset)) + dragAndDropState.onTargeting(it.index, insertAfter(it, relativeDragOffset)) } } @@ -147,8 +163,8 @@ fun Modifier.dragAndDropTileList( ) } -private fun DragAndDropEvent.dragOffsetRelativeTo(offset: Offset): Offset { - return toAndroidDragEvent().run { Offset(x, y) } - offset +private fun DragAndDropEvent.toOffset(): Offset { + return toAndroidDragEvent().run { Offset(x, y) } } private fun insertAfter(item: LazyGridItemInfo, offset: Offset): Boolean { @@ -163,6 +179,7 @@ private fun insertAfter(item: LazyGridItemInfo, offset: Offset): Boolean { fun Modifier.dragAndDropTileSource( sizedTile: SizedTile<EditTileViewModel>, dragAndDropState: DragAndDropState, + dragType: DragType, onDragStart: () -> Unit, ): Modifier { val dragState by rememberUpdatedState(dragAndDropState) @@ -172,7 +189,7 @@ fun Modifier.dragAndDropTileSource( detectDragGesturesAfterLongPress( onDrag = { _, _ -> }, onDragStart = { - dragState.onStarted(sizedTile) + dragState.onStarted(sizedTile, dragType) onDragStart() // The tilespec from the ClipData transferred isn't actually needed as we're diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt index 14abfa2313d8..868855840922 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt @@ -17,10 +17,13 @@ package com.android.systemui.qs.panels.ui.compose import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.runtime.toMutableStateList +import androidx.compose.ui.geometry.Offset import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.ui.model.GridCell import com.android.systemui.qs.panels.ui.model.TileGridCell @@ -48,12 +51,17 @@ class EditTileListState( private val columns: Int, private val largeTilesSpan: Int, ) : DragAndDropState { - private val _draggedCell = mutableStateOf<SizedTile<EditTileViewModel>?>(null) - override val draggedCell - get() = _draggedCell.value + override var draggedCell by mutableStateOf<SizedTile<EditTileViewModel>?>(null) + private set + + override var draggedPosition by mutableStateOf(Offset.Unspecified) + private set + + override var dragType by mutableStateOf<DragType?>(null) + private set override val dragInProgress: Boolean - get() = _draggedCell.value != null + get() = draggedCell != null private val _tiles: SnapshotStateList<GridCell> = tiles.toGridCells(columns).toMutableStateList() @@ -83,18 +91,19 @@ class EditTileListState( } override fun isMoving(tileSpec: TileSpec): Boolean { - return _draggedCell.value?.let { it.tile.tileSpec == tileSpec } ?: false + return draggedCell?.let { it.tile.tileSpec == tileSpec } ?: false } - override fun onStarted(cell: SizedTile<EditTileViewModel>) { - _draggedCell.value = cell + override fun onStarted(cell: SizedTile<EditTileViewModel>, dragType: DragType) { + draggedCell = cell + this.dragType = dragType // Add spacers to the grid to indicate where the user can move a tile regenerateGrid() } - override fun onMoved(target: Int, insertAfter: Boolean) { - val draggedTile = _draggedCell.value ?: return + override fun onTargeting(target: Int, insertAfter: Boolean) { + val draggedTile = draggedCell ?: return val fromIndex = indexOf(draggedTile.tile.tileSpec) if (fromIndex == target) { @@ -115,16 +124,26 @@ class EditTileListState( regenerateGrid() } + override fun onMoved(offset: Offset) { + draggedPosition = offset + } + override fun movedOutOfBounds() { - val draggedTile = _draggedCell.value ?: return + val draggedTile = draggedCell ?: return _tiles.removeIf { cell -> cell is TileGridCell && cell.tile.tileSpec == draggedTile.tile.tileSpec } + draggedPosition = Offset.Unspecified + + // Regenerate spacers without the dragged tile + regenerateGrid() } override fun onDrop() { - _draggedCell.value = null + draggedCell = null + draggedPosition = Offset.Unspecified + dragType = null // Remove the spacers regenerateGrid() diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt index b6dbf4db57a4..39408d3dee72 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt @@ -49,9 +49,10 @@ import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.qs.panels.dagger.PaginatedBaseLayoutType import com.android.systemui.qs.panels.ui.compose.Dimensions.FooterHeight import com.android.systemui.qs.panels.ui.compose.Dimensions.InterPageSpacing -import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel +import com.android.systemui.qs.panels.ui.compose.toolbar.EditModeButton import com.android.systemui.qs.panels.ui.viewmodel.PaginatedGridViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.EditModeButtonViewModel import com.android.systemui.qs.ui.compose.borderOnFocus import javax.inject.Inject diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt index c6141a1a7cc2..d975f104d538 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt @@ -20,14 +20,19 @@ package com.android.systemui.qs.panels.ui.compose.infinitegrid import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.animateContentSize +import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.LocalOverscrollFactory +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clipScrollableContainer import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box @@ -42,6 +47,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeightIn import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentSize @@ -68,6 +74,7 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -79,6 +86,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.isSpecified import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.MeasureScope @@ -110,6 +118,7 @@ import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.shared.model.SizedTileImpl import com.android.systemui.qs.panels.ui.compose.BounceableInfo import com.android.systemui.qs.panels.ui.compose.DragAndDropState +import com.android.systemui.qs.panels.ui.compose.DragType import com.android.systemui.qs.panels.ui.compose.EditTileListState import com.android.systemui.qs.panels.ui.compose.bounceableInfo import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone @@ -119,6 +128,9 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileArrangementPadding import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ToggleTargetSize +import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_DISTANCE +import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_SPEED +import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AvailableTilesGridMinHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer @@ -138,9 +150,10 @@ import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.shared.model.groupAndSort import com.android.systemui.res.R -import kotlin.math.max +import kotlin.math.abs import kotlin.math.roundToInt import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay object TileType @@ -148,8 +161,9 @@ object TileType @OptIn(ExperimentalMaterial3Api::class) @Composable private fun EditModeTopBar(onStopEditing: () -> Unit, onReset: (() -> Unit)?) { + TopAppBar( - colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Black), + colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), title = { Text(text = stringResource(id = R.string.qs_edit)) }, navigationIcon = { IconButton(onClick = onStopEditing) { @@ -200,8 +214,12 @@ fun DefaultEditTileGrid( ) { innerPadding -> CompositionLocalProvider(LocalOverscrollFactory provides null) { val scrollState = rememberScrollState() - LaunchedEffect(listState.dragInProgress) { - if (listState.dragInProgress) { + + AutoScrollGrid(listState, scrollState, innerPadding) + + LaunchedEffect(listState.dragType) { + // Only scroll to the top when adding a new tile, not when reordering existing ones + if (listState.dragInProgress && listState.dragType == DragType.Add) { scrollState.animateScrollTo(0) } } @@ -209,12 +227,20 @@ fun DefaultEditTileGrid( Column( verticalArrangement = spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)), - modifier = modifier.fillMaxSize().verticalScroll(scrollState).padding(innerPadding), + modifier = + modifier + .fillMaxSize() + // Apply top padding before the scroll so the scrollable doesn't show under + // the + // top bar + .padding(top = innerPadding.calculateTopPadding()) + .clipScrollableContainer(Orientation.Vertical) + .verticalScroll(scrollState), ) { AnimatedContent( targetState = listState.dragInProgress, modifier = Modifier.wrapContentSize(), - label = "", + label = "QSEditHeader", ) { dragIsInProgress -> EditGridHeader(Modifier.dragAndDropRemoveZone(listState, onRemoveTile)) { if (dragIsInProgress) { @@ -234,34 +260,84 @@ fun DefaultEditTileGrid( onSetTiles, ) - // Hide available tiles when dragging - AnimatedVisibility( - visible = !listState.dragInProgress, - enter = fadeIn(), - exit = fadeOut(), + // Sets a minimum height to be used when available tiles are hidden + Box( + Modifier.fillMaxWidth() + .requiredHeightIn(AvailableTilesGridMinHeight) + .animateContentSize() + .dragAndDropRemoveZone(listState, onRemoveTile) ) { - Column( - verticalArrangement = - spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)), - modifier = modifier.fillMaxSize(), + // Using the fully qualified name here as a workaround for AnimatedVisibility + // not being available from a Box + androidx.compose.animation.AnimatedVisibility( + visible = !listState.dragInProgress, + enter = fadeIn(), + exit = fadeOut(), ) { - EditGridHeader { - Text(text = stringResource(id = R.string.drag_to_add_tiles)) - } + // Hide available tiles when dragging + Column( + verticalArrangement = + spacedBy(dimensionResource(id = R.dimen.qs_label_container_margin)), + modifier = modifier.fillMaxSize(), + ) { + EditGridHeader { + Text(text = stringResource(id = R.string.drag_to_add_tiles)) + } - AvailableTileGrid(otherTiles, selectionState, columns, listState) + AvailableTileGrid(otherTiles, selectionState, columns, listState) + } } } + } + } + } +} - // Drop zone to remove tiles dragged out of the tile grid - Spacer( - modifier = - Modifier.fillMaxWidth() - .weight(1f) - .dragAndDropRemoveZone(listState, onRemoveTile) - ) +@OptIn(ExperimentalCoroutinesApi::class) +@Composable +private fun AutoScrollGrid( + listState: EditTileListState, + scrollState: ScrollState, + padding: PaddingValues, +) { + val density = LocalDensity.current + val (top, bottom) = + remember(density) { + with(density) { + padding.calculateTopPadding().roundToPx() to + padding.calculateBottomPadding().roundToPx() + } + } + val scrollTarget by + remember(listState, scrollState, top, bottom) { + derivedStateOf { + val position = listState.draggedPosition + if (position.isSpecified) { + // Return the scroll target needed based on the position of the drag movement, + // or null if we don't need to scroll + val y = position.y.roundToInt() + when { + y < AUTO_SCROLL_DISTANCE + top -> 0 + y > scrollState.viewportSize - bottom - AUTO_SCROLL_DISTANCE -> + scrollState.maxValue + else -> null + } + } else { + null + } } } + LaunchedEffect(scrollTarget) { + scrollTarget?.let { + // Change the duration of the animation based on the distance to maintain the + // same scrolling speed + val distance = abs(it - scrollState.value) + scrollState.animateScrollTo( + it, + animationSpec = + tween(durationMillis = distance * AUTO_SCROLL_SPEED, easing = LinearEasing), + ) + } } } @@ -414,7 +490,7 @@ private fun AvailableTileGrid( } fun gridHeight(rows: Int, tileHeight: Dp, tilePadding: Dp, gridPadding: Dp): Dp { - return ((tileHeight + tilePadding) * rows) - tilePadding + gridPadding * 2 + return ((tileHeight + tilePadding) * rows) + gridPadding * 2 } private fun GridCell.key(index: Int, dragAndDropState: DragAndDropState): Any { @@ -587,6 +663,7 @@ private fun TileGridCell( .dragAndDropTileSource( SizedTileImpl(cell.tile, cell.width), dragAndDropState, + DragType.Move, selectionState::unSelect, ) .tileBackground(colors.background) @@ -622,7 +699,11 @@ private fun AvailableTileGridCell( onClick(onClickActionName) { false } this.stateDescription = stateDescription } - .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) { + .dragAndDropTileSource( + SizedTileImpl(cell.tile, cell.width), + dragAndDropState, + DragType.Add, + ) { selectionState.unSelect() } .tileBackground(colors.background) @@ -730,7 +811,10 @@ private fun Modifier.tileBackground(color: Color): Modifier { private object EditModeTileDefaults { const val PLACEHOLDER_ALPHA = .3f + const val AUTO_SCROLL_DISTANCE = 100 + const val AUTO_SCROLL_SPEED = 2 // 2ms per pixel val CurrentTilesGridPadding = 8.dp + val AvailableTilesGridMinHeight = 200.dp @Composable fun editTileColors(): TileColors = diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt index c2764f9f338b..85db95203b45 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditModeButton.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.ui.compose +package com.android.systemui.qs.panels.ui.compose.toolbar import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape @@ -30,7 +30,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.android.systemui.lifecycle.rememberViewModel -import com.android.systemui.qs.panels.ui.viewmodel.EditModeButtonViewModel +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.EditModeButtonViewModel import com.android.systemui.qs.ui.compose.borderOnFocus import com.android.systemui.res.R diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt new file mode 100644 index 000000000000..37fa9e799521 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.ui.compose.toolbar + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.requiredHeight +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.android.systemui.compose.modifiers.sysuiResTag +import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.qs.footer.ui.compose.IconButton +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel + +@Composable +fun Toolbar(toolbarViewModelFactory: ToolbarViewModel.Factory, modifier: Modifier = Modifier) { + val viewModel = rememberViewModel("Toolbar") { toolbarViewModelFactory.create() } + + Row( + modifier = modifier.fillMaxWidth().requiredHeight(48.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + viewModel.userSwitcherViewModel?.let { + IconButton(it, Modifier.sysuiResTag("multi_user_switch")) + } + + EditModeButton(viewModel.editModeButtonViewModelFactory) + + IconButton( + viewModel.settingsButtonViewModel, + Modifier.sysuiResTag("settings_button_container"), + ) + + Spacer(modifier = Modifier.weight(1f)) + IconButton(viewModel.powerButtonViewModel, Modifier.sysuiResTag("pm_lite")) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt index faab6960a99c..f7ed1adecb34 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt @@ -18,9 +18,14 @@ package com.android.systemui.qs.panels.ui.viewmodel import android.content.Context import androidx.compose.ui.util.fastMap +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListUpdateCallback +import com.android.internal.logging.UiEventLogger import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.qs.QSEditEvent import com.android.systemui.qs.panels.domain.interactor.EditTilesListInteractor import com.android.systemui.qs.panels.domain.interactor.GridLayoutTypeInteractor import com.android.systemui.qs.panels.domain.interactor.TilesAvailabilityInteractor @@ -30,10 +35,12 @@ import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor.Companion.POSITION_AT_END import com.android.systemui.qs.pipeline.domain.interactor.MinimumTilesInteractor import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.metricSpec import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.util.kotlin.emitOnStart import javax.inject.Inject import javax.inject.Named +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -45,6 +52,7 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch @SysUISingleton @OptIn(ExperimentalCoroutinesApi::class) @@ -55,10 +63,12 @@ constructor( private val currentTilesInteractor: CurrentTilesInteractor, private val tilesAvailabilityInteractor: TilesAvailabilityInteractor, private val minTilesInteractor: MinimumTilesInteractor, + private val uiEventLogger: UiEventLogger, @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor, - @ShadeDisplayAware private val context: Context, + @ShadeDisplayAware private val context: Context, @Named("Default") private val defaultGridLayout: GridLayout, @Application private val applicationScope: CoroutineScope, + @Background private val bgDispatcher: CoroutineDispatcher, gridLayoutTypeInteractor: GridLayoutTypeInteractor, gridLayoutMap: Map<GridLayoutType, @JvmSuppressWildcards GridLayout>, ) { @@ -149,11 +159,17 @@ constructor( /** @see isEditing */ fun startEditing() { + if (!isEditing.value) { + uiEventLogger.log(QSEditEvent.QS_EDIT_OPEN) + } _isEditing.value = true } /** @see isEditing */ fun stopEditing() { + if (isEditing.value) { + uiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED) + } _isEditing.value = false } @@ -164,6 +180,7 @@ constructor( fun addTile(tileSpec: TileSpec, position: Int = POSITION_AT_END) { val specs = currentTilesInteractor.currentTilesSpecs.toMutableList() val currentPosition = specs.indexOf(tileSpec) + val moved = currentPosition != -1 if (currentPosition != -1) { // No operation needed if the element is already in the list at the right position @@ -179,6 +196,12 @@ constructor( } else { specs.add(tileSpec) } + uiEventLogger.logWithPosition( + if (moved) QSEditEvent.QS_EDIT_MOVE else QSEditEvent.QS_EDIT_ADD, + /* uid= */ 0, + /* packageName= */ tileSpec.metricSpec, + if (moved && position == POSITION_AT_END) specs.size - 1 else position, + ) // Setting the new tiles as one operation to avoid UI jank with tiles disappearing and // reappearing @@ -187,10 +210,80 @@ constructor( /** Immediately removes [tileSpec] from the current tiles. */ fun removeTile(tileSpec: TileSpec) { + uiEventLogger.log( + QSEditEvent.QS_EDIT_REMOVE, + /* uid= */ 0, + /* packageName= */ tileSpec.metricSpec, + ) currentTilesInteractor.removeTiles(listOf(tileSpec)) } fun setTiles(tileSpecs: List<TileSpec>) { + val currentTiles = currentTilesInteractor.currentTilesSpecs currentTilesInteractor.setTiles(tileSpecs) + applicationScope.launch(bgDispatcher) { + calculateDiffsAndEmitUiEvents(currentTiles, tileSpecs) + } + } + + private fun calculateDiffsAndEmitUiEvents( + currentTiles: List<TileSpec>, + newTiles: List<TileSpec>, + ) { + val listDiff = DiffUtil.calculateDiff(DiffCallback(currentTiles, newTiles)) + listDiff.dispatchUpdatesTo( + object : ListUpdateCallback { + override fun onInserted(position: Int, count: Int) { + newTiles.getOrNull(position)?.let { + uiEventLogger.logWithPosition( + QSEditEvent.QS_EDIT_ADD, + /* uid= */ 0, + /* packageName= */ it.metricSpec, + position, + ) + } + } + + override fun onRemoved(position: Int, count: Int) { + currentTiles.getOrNull(position)?.let { + uiEventLogger.log(QSEditEvent.QS_EDIT_REMOVE, 0, it.metricSpec) + } + } + + override fun onMoved(fromPosition: Int, toPosition: Int) { + currentTiles.getOrNull(fromPosition)?.let { + uiEventLogger.logWithPosition( + QSEditEvent.QS_EDIT_MOVE, + /* uid= */ 0, + /* packageName= */ it.metricSpec, + toPosition, + ) + } + } + + override fun onChanged(position: Int, count: Int, payload: Any?) {} + } + ) + } +} + +private class DiffCallback( + private val currentList: List<TileSpec>, + private val newList: List<TileSpec>, +) : DiffUtil.Callback() { + override fun getOldListSize(): Int { + return currentList.size + } + + override fun getNewListSize(): Int { + return newList.size + } + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return currentList[oldItemPosition] == newList[newItemPosition] + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return areItemsTheSame(oldItemPosition, newItemPosition) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt index 4a18872ad6f6..3fcb2ab37b0f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt @@ -24,6 +24,7 @@ import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS import com.android.systemui.qs.panels.domain.interactor.PaginatedGridInteractor +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.EditModeButtonViewModel import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.awaitCancellation diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModel.kt index b033473a91e5..f60621882ac0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModel.kt @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.ui.viewmodel +package com.android.systemui.qs.panels.ui.viewmodel.toolbar import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.plugins.FalsingManager +import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt new file mode 100644 index 000000000000..0fde855f576f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.ui.viewmodel.toolbar + +import android.content.Context +import android.view.ContextThemeWrapper +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import com.android.systemui.animation.Expandable +import com.android.systemui.classifier.domain.interactor.FalsingInteractor +import com.android.systemui.classifier.domain.interactor.runIfNotFalseTap +import com.android.systemui.globalactions.GlobalActionsDialogLite +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator +import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor +import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel +import com.android.systemui.qs.footer.ui.viewmodel.powerButtonViewModel +import com.android.systemui.qs.footer.ui.viewmodel.settingsButtonViewModel +import com.android.systemui.qs.footer.ui.viewmodel.userSwitcherViewModel +import com.android.systemui.res.R +import com.android.systemui.shade.ShadeDisplayAware +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import javax.inject.Provider +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +class ToolbarViewModel +@AssistedInject +constructor( + val editModeButtonViewModelFactory: EditModeButtonViewModel.Factory, + private val footerActionsInteractor: FooterActionsInteractor, + private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, + private val falsingInteractor: FalsingInteractor, + @ShadeDisplayAware appContext: Context, +) : ExclusiveActivatable() { + private val qsThemedContext = + ContextThemeWrapper(appContext, R.style.Theme_SystemUI_QuickSettings) + private val hydrator = Hydrator("ToolbarViewModel.hydrator") + + val powerButtonViewModel = powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked) + + val settingsButtonViewModel = + settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked) + + val userSwitcherViewModel: FooterActionsButtonViewModel? by + hydrator.hydratedStateOf( + traceName = "userSwitcherViewModel", + initialValue = null, + source = + userSwitcherViewModel( + qsThemedContext, + footerActionsInteractor, + ::onUserSwitcherClicked, + ), + ) + + override suspend fun onActivated(): Nothing { + coroutineScope { + launch { + try { + globalActionsDialogLite = globalActionsDialogLiteProvider.get() + awaitCancellation() + } finally { + globalActionsDialogLite?.destroy() + } + } + launch { hydrator.activate() } + awaitCancellation() + } + } + + private var globalActionsDialogLite: GlobalActionsDialogLite? by mutableStateOf(null) + + private fun onPowerButtonClicked(expandable: Expandable) { + falsingInteractor.runIfNotFalseTap { + globalActionsDialogLite?.let { + footerActionsInteractor.showPowerMenuDialog(it, expandable) + } + } + } + + private fun onUserSwitcherClicked(expandable: Expandable) { + falsingInteractor.runIfNotFalseTap { footerActionsInteractor.showUserSwitcher(expandable) } + } + + private fun onSettingsButtonClicked(expandable: Expandable) { + falsingInteractor.runIfNotFalseTap { footerActionsInteractor.showSettings(expandable) } + } + + @AssistedFactory + interface Factory { + fun create(): ToolbarViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt index 2e52845ceb80..16c27223a471 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/TileSpec.kt @@ -34,10 +34,7 @@ sealed class TileSpec private constructor(open val spec: String) { data object Invalid : TileSpec("") /** Container for the spec of a tile provided by SystemUI. */ - data class PlatformTileSpec - internal constructor( - override val spec: String, - ) : TileSpec(spec) { + data class PlatformTileSpec internal constructor(override val spec: String) : TileSpec(spec) { override fun toString(): String { return "P($spec)" } @@ -49,10 +46,8 @@ sealed class TileSpec private constructor(open val spec: String) { * [componentName] indicates the associated `TileService`. */ data class CustomTileSpec - internal constructor( - override val spec: String, - val componentName: ComponentName, - ) : TileSpec(spec) { + internal constructor(override val spec: String, val componentName: ComponentName) : + TileSpec(spec) { override fun toString(): String { return "C(${componentName.flattenToShortString()})" } @@ -92,3 +87,11 @@ sealed class TileSpec private constructor(open val spec: String) { } } } + +val TileSpec.metricSpec + get() = + when (this) { + is TileSpec.Invalid -> "" + is TileSpec.PlatformTileSpec -> spec + is TileSpec.CustomTileSpec -> componentName.packageName + } 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/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt index dde36289f139..5f476ea7e274 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt @@ -17,18 +17,17 @@ package com.android.systemui.qs.tiles.base.viewmodel import com.android.systemui.coroutines.newTracingContext -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob /** Creates a [CoroutineScope] for the [QSTileViewModelImpl]. */ class QSTileCoroutineScopeFactory @Inject -constructor(@Application private val applicationScope: CoroutineScope) { +constructor(@Background private val bgDispatcher: CoroutineDispatcher) { fun create(): CoroutineScope = - CoroutineScope( - applicationScope.coroutineContext + SupervisorJob() + newTracingContext("QSTileScope") - ) + CoroutineScope(bgDispatcher + SupervisorJob() + newTracingContext("QSTileScope")) } 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/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt index 62b120332289..91d907952bc6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt @@ -22,6 +22,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -38,6 +39,7 @@ constructor( val tileGridViewModel: TileGridViewModel, val editModeViewModel: EditModeViewModel, val detailsViewModel: DetailsViewModel, + val toolbarViewModelFactory: ToolbarViewModel.Factory, ) : ExclusiveActivatable() { val brightnessSliderViewModel = 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/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index fc4db0877dbe..b7a3aedc565e 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -31,6 +31,8 @@ import android.os.UserManager import android.util.Log import androidx.annotation.GuardedBy import androidx.annotation.WorkerThread +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.app.tracing.traceSection import com.android.systemui.Dumpable import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlagsClassic @@ -49,7 +51,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.sync.Mutex /** @@ -314,7 +315,9 @@ internal constructor( list.forEach { val callback = it.callback.get() if (callback != null) { - it.executor.execute { action(callback) { latch.countDown() } } + it.executor.execute { + traceSection({ "$callback" }) { action(callback) { latch.countDown() } } + } } else { latch.countDown() } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java index 30b6892731f1..c241f2165c8f 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java @@ -62,7 +62,7 @@ public class ToggleSeekBar extends SeekBar { } else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) { setHovered(false); } - return true; + return super.onHoverEvent(event); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 31780a56f7f0..61ac1a029f1f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -41,11 +41,11 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.theme.PlatformTheme import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Flags -import com.android.systemui.Flags.communalHubOnMobile import com.android.systemui.ambient.touch.TouchMonitor import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent import com.android.systemui.communal.dagger.Communal import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.ui.compose.CommunalContainer import com.android.systemui.communal.ui.compose.CommunalContent import com.android.systemui.communal.ui.viewmodel.CommunalViewModel @@ -83,6 +83,7 @@ class GlanceableHubContainerController @Inject constructor( private val communalInteractor: CommunalInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, private val communalViewModel: CommunalViewModel, private val keyguardInteractor: KeyguardInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, @@ -514,7 +515,7 @@ constructor( val touchOnUmo = keyguardMediaController.isWithinMediaViewBounds(ev.x.toInt(), ev.y.toInt()) val touchOnSmartspace = lockscreenSmartspaceController.isWithinSmartspaceBounds(ev.x.toInt(), ev.y.toInt()) - val glanceableHubV2 = communalHubOnMobile() + val glanceableHubV2 = communalSettingsInteractor.isV2FlagEnabled() if ( !hubShowing && (touchOnNotifications || touchOnUmo || touchOnSmartspace || glanceableHubV2) diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java index f5fc1f414f82..bf672be3c8d0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java @@ -166,6 +166,15 @@ public class NotificationShadeWindowView extends WindowRootView { } @Override + public void onMovedToDisplay(int displayId, Configuration config) { + super.onMovedToDisplay(displayId, config); + ShadeWindowGoesAround.isUnexpectedlyInLegacyMode(); + // When the window is moved we're only receiving a call to this method instead of the + // onConfigurationChange itself. Let's just trigegr a normal config change. + onConfigurationChanged(config); + } + + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (mConfigurationForwarder != null) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt index ff39a3ddc17c..d31868ca0217 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt @@ -22,15 +22,16 @@ import android.view.LayoutInflater import android.view.WindowManager import android.view.WindowManager.LayoutParams import android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE +import android.window.WindowContext import com.android.systemui.CoreStartable import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.common.ui.ConfigurationStateImpl -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository @@ -48,6 +49,7 @@ import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap import javax.inject.Provider +import javax.inject.Qualifier /** * Module responsible for managing display-specific components and resources for the notification @@ -81,6 +83,19 @@ object ShadeDisplayAwareModule { @Provides @ShadeDisplayAware @SysUISingleton + fun provideShadeDisplayAwareWindowContext(@ShadeDisplayAware context: Context): WindowContext { + ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() + // We rely on the fact context is a WindowContext as the API to reparent windows is only + // available there. + return (context as? WindowContext) + ?: error( + "ShadeDisplayAware context must be a window context to allow window reparenting." + ) + } + + @Provides + @ShadeDisplayAware + @SysUISingleton fun provideShadeWindowLayoutParams(@ShadeDisplayAware context: Context): LayoutParams { return ShadeWindowLayoutParams.create(context) } @@ -119,7 +134,7 @@ object ShadeDisplayAwareModule { fun provideShadeWindowConfigurationController( @ShadeDisplayAware shadeContext: Context, factory: ConfigurationControllerImpl.Factory, - @GlobalConfig globalConfigController: ConfigurationController, + @Main globalConfigController: ConfigurationController, ): ConfigurationController { return if (ShadeWindowGoesAround.isEnabled) { factory.create(shadeContext) @@ -145,7 +160,7 @@ object ShadeDisplayAwareModule { factory: ConfigurationStateImpl.Factory, @ShadeDisplayAware configurationController: ConfigurationController, @ShadeDisplayAware context: Context, - @GlobalConfig configurationState: ConfigurationState, + @Main configurationState: ConfigurationState, ): ConfigurationState { return if (ShadeWindowGoesAround.isEnabled) { factory.create(context, configurationController) @@ -161,7 +176,7 @@ object ShadeDisplayAwareModule { factory: ConfigurationRepositoryImpl.Factory, @ShadeDisplayAware configurationController: ConfigurationController, @ShadeDisplayAware context: Context, - @GlobalConfig globalConfigurationRepository: ConfigurationRepository, + @Main globalConfigurationRepository: ConfigurationRepository, ): ConfigurationRepository { return if (ShadeWindowGoesAround.isEnabled) { factory.create(context, configurationController) @@ -175,7 +190,7 @@ object ShadeDisplayAwareModule { @ShadeDisplayAware fun provideShadeAwareConfigurationInteractor( @ShadeDisplayAware configurationRepository: ConfigurationRepository, - @GlobalConfig configurationInteractor: ConfigurationInteractor, + @Main configurationInteractor: ConfigurationInteractor, ): ConfigurationInteractor { return if (ShadeWindowGoesAround.isEnabled) { ConfigurationInteractorImpl(configurationRepository) @@ -203,7 +218,9 @@ object ShadeDisplayAwareModule { @Provides @IntoMap @ClassKey(ShadePrimaryDisplayCommand::class) - fun provideShadePrimaryDisplayCommand(impl: Provider<ShadePrimaryDisplayCommand>): CoreStartable { + fun provideShadePrimaryDisplayCommand( + impl: Provider<ShadePrimaryDisplayCommand> + ): CoreStartable { return if (ShadeWindowGoesAround.isEnabled) { impl.get() } else { @@ -221,9 +238,23 @@ object ShadeDisplayAwareModule { CoreStartable.NOP } } + + @Provides + @ShadeOnDefaultDisplayWhenLocked + fun provideShadeOnDefaultDisplayWhenLocked(): Boolean = true } @Module internal interface OptionalShadeDisplayAwareBindings { @BindsOptionalOf fun bindOptionalOfWindowRootView(): WindowRootView } + +/** + * Annotates the boolean value that defines whether the shade window should go back to the default + * display when the keyguard is visible. + * + * As of today (Dec 2024), This is a configuration parameter provided in the dagger graph as the + * final policy around keyguard display is still under discussion, and will be evaluated based on + * how well this solution behaves from the performance point of view. + */ +@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class ShadeOnDefaultDisplayWhenLocked diff --git a/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt index ae36e81c7b1f..29c7aa0680d3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt @@ -21,13 +21,18 @@ import android.view.GestureDetector import android.view.GestureDetector.SimpleOnGestureListener import android.view.MotionEvent import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import javax.inject.Inject /** Accepts touch events, detects long press, and calls ShadeViewController#onStatusBarLongPress. */ @SysUISingleton class StatusBarLongPressGestureDetector @Inject -constructor(context: Context, val shadeViewController: ShadeViewController) { +constructor( + // TODO b/383125226 - Make this class per-display + @Main context: Context, + val shadeViewController: ShadeViewController, +) { val gestureDetector = GestureDetector( context, diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt index 22e9487af84c..30b086f03d66 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt @@ -22,34 +22,55 @@ import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DisplayRepository +import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn /** * Moves the shade on the last display that received a status bar touch. * - * If the display is removed, falls back to the default one. + * If the display is removed, falls back to the default one. When [shadeOnDefaultDisplayWhenLocked] + * is true, the shade falls back to the default display when the keyguard is visible. */ @SysUISingleton class StatusBarTouchShadeDisplayPolicy @Inject -constructor(displayRepository: DisplayRepository, @Background val backgroundScope: CoroutineScope) : - ShadeDisplayPolicy { - override val name: String - get() = "status_bar_latest_touch" +constructor( + displayRepository: DisplayRepository, + keyguardRepository: KeyguardRepository, + @Background val backgroundScope: CoroutineScope, + @ShadeOnDefaultDisplayWhenLocked val shadeOnDefaultDisplayWhenLocked: Boolean, +) : ShadeDisplayPolicy { + override val name: String = "status_bar_latest_touch" private val currentDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY) private val availableDisplayIds: StateFlow<Set<Int>> = displayRepository.displayIds - override val displayId: StateFlow<Int> - get() = currentDisplayId + override val displayId: StateFlow<Int> = + if (shadeOnDefaultDisplayWhenLocked) { + keyguardRepository.isKeyguardShowing + .combine(currentDisplayId) { isKeyguardShowing, currentDisplayId -> + if (isKeyguardShowing) { + Display.DEFAULT_DISPLAY + } else { + currentDisplayId + } + } + .stateIn(backgroundScope, SharingStarted.WhileSubscribed(), currentDisplayId.value) + } else { + currentDisplayId + } private var removalListener: Job? = null diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt index 34148671cf2a..08c03e28d596 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt @@ -16,10 +16,8 @@ package com.android.systemui.shade.domain.interactor -import android.content.Context import android.util.Log -import android.view.WindowManager -import android.view.WindowManager.LayoutParams +import android.window.WindowContext import androidx.annotation.UiThread import com.android.app.tracing.coroutines.launchTraced import com.android.app.tracing.traceSection @@ -45,9 +43,7 @@ class ShadeDisplaysInteractor constructor( optionalShadeRootView: Optional<WindowRootView>, private val shadePositionRepository: ShadeDisplaysRepository, - @ShadeDisplayAware private val shadeContext: Context, - @ShadeDisplayAware private val shadeLayoutParams: LayoutParams, - @ShadeDisplayAware private val wm: WindowManager, + @ShadeDisplayAware private val shadeContext: WindowContext, @Background private val bgScope: CoroutineScope, @Main private val mainThreadContext: CoroutineContext, ) : CoreStartable { @@ -72,7 +68,11 @@ constructor( /** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */ private suspend fun moveShadeWindowTo(destinationId: Int) { Log.d(TAG, "Trying to move shade window to display with id $destinationId") - val currentDisplay = shadeRootView.display + // Why using the shade context here instead of the view's Display? + // The context's display is updated before the view one, so it is a better indicator of + // which display the shade is supposed to be at. The View display is updated after the first + // rendering with the new config. + val currentDisplay = shadeContext.display if (currentDisplay == null) { Log.w(TAG, "Current shade display is null") return @@ -83,7 +83,7 @@ constructor( return } try { - withContext(mainThreadContext) { moveShadeWindow(toId = destinationId) } + withContext(mainThreadContext) { reparentToDisplayId(id = destinationId) } } catch (e: IllegalStateException) { Log.e( TAG, @@ -94,25 +94,8 @@ constructor( } @UiThread - private fun moveShadeWindow(toId: Int) { - traceSection({ "moveShadeWindow to $toId" }) { - removeShadeWindow() - updateContextDisplay(toId) - addShadeWindow() - } - } - - @UiThread - private fun removeShadeWindow(): Unit = - traceSection("removeShadeWindow") { wm.removeView(shadeRootView) } - - @UiThread - private fun addShadeWindow(): Unit = - traceSection("addShadeWindow") { wm.addView(shadeRootView, shadeLayoutParams) } - - @UiThread - private fun updateContextDisplay(newDisplayId: Int) { - traceSection("updateContextDisplay") { shadeContext.updateDisplay(newDisplayId) } + private fun reparentToDisplayId(id: Int) { + traceSection({ "reparentToDisplayId(id=$id)" }) { shadeContext.reparentToDisplay(id) } } private companion object { 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..d0dc7ac386c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -78,7 +78,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; -import com.android.settingslib.Utils; import com.android.systemui.res.R; import com.android.systemui.statusbar.phone.CentralSurfaces; @@ -768,8 +767,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 +775,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, }; @@ -1422,13 +1415,11 @@ public final class KeyboardShortcutListSearch { } private int getColorOfTextColorOnAccent() { - return Utils.getColorAttrDefaultColor( - mContext, com.android.internal.R.attr.materialColorOnPrimary); + return mContext.getColor(com.android.internal.R.color.materialColorOnPrimary); } private int getColorOfTextColorSecondary() { - return Utils.getColorAttrDefaultColor( - mContext, com.android.internal.R.attr.materialColorOnSurface); + return mContext.getColor(com.android.internal.R.color.materialColorOnSurface); } // Create the new data structure for handling the N-to-1 key mapping and other complex case. 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/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt index 6f491e7beec8..85b50d3320dd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -67,9 +68,17 @@ constructor( Flags.statusBarCallChipNotificationIcon() && state.notificationIconView != null ) { + StatusBarConnectedDisplays.assertInLegacyMode() OngoingActivityChipModel.ChipIcon.StatusBarView( state.notificationIconView ) + } else if ( + StatusBarConnectedDisplays.isEnabled && + Flags.statusBarCallChipNotificationIcon() + ) { + OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon( + state.notificationKey + ) } else { OngoingActivityChipModel.ChipIcon.SingleColorIcon(phoneIcon) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt index c57c807360b1..bbecde830a9f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt @@ -22,6 +22,7 @@ import com.android.systemui.log.core.Logger import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad import com.android.systemui.statusbar.chips.StatusBarChipsLog import com.android.systemui.statusbar.chips.notification.domain.model.NotificationChipModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -56,6 +57,14 @@ constructor( // top-level tag. It should instead be provided as the first string in each log message. private val extraLogTag = "SingleChipInteractor[key=$key]" + init { + if (startingModel.promotedContent == null) { + logger.e({ "$str1: Starting model has promotedContent=null, which shouldn't happen" }) { + str1 = extraLogTag + } + } + } + private val _notificationModel = MutableStateFlow(startingModel) /** @@ -70,6 +79,14 @@ constructor( } return } + if (model.promotedContent == null) { + logger.e({ + "$str1: received model with promotedContent=null, which shouldn't happen" + }) { + str1 = extraLogTag + } + return + } _notificationModel.value = model } @@ -98,14 +115,29 @@ constructor( } private fun ActiveNotificationModel.toNotificationChipModel(): NotificationChipModel? { - val statusBarChipIconView = this.statusBarChipIconView - if (statusBarChipIconView == null) { - logger.w({ "$str1: Can't show chip because status bar chip icon view is null" }) { + val promotedContent = this.promotedContent + if (promotedContent == null) { + logger.w({ + "$str1: Can't show chip because promotedContent=null, which shouldn't happen" + }) { str1 = extraLogTag } return null } - return NotificationChipModel(key, statusBarChipIconView, whenTime) + val statusBarChipIconView = this.statusBarChipIconView + if (statusBarChipIconView == null) { + if (!StatusBarConnectedDisplays.isEnabled) { + logger.w({ "$str1: Can't show chip because status bar chip icon view is null" }) { + str1 = extraLogTag + } + // When the flag is disabled, we keep the old behavior of returning null. + // When the flag is enabled, the icon will always be null, and will later be + // fetched in the UI layer using the notification key. + return null + } + } + + return NotificationChipModel(key, statusBarChipIconView, whenTime, promotedContent) } @AssistedFactory diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt index bc4241d9bca5..9f0638baec83 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt @@ -17,10 +17,13 @@ package com.android.systemui.statusbar.chips.notification.domain.model import com.android.systemui.statusbar.StatusBarIconView +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel /** Modeling all the data needed to render a status bar notification chip. */ data class NotificationChipModel( val key: String, - val statusBarChipIconView: StatusBarIconView, + val statusBarChipIconView: StatusBarIconView?, + // TODO(b/364653005): Use [PromotedNotificationContentModel.time] instead of a custom field. val whenTime: Long, + val promotedContent: PromotedNotificationContentModel, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index b2f7e2fe7660..e2c886a0f680 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.chips.notification.domain.model.Notificati import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -50,9 +51,19 @@ constructor( /** Converts the notification to the [OngoingActivityChipModel] object. */ private fun NotificationChipModel.toActivityChipModel(): OngoingActivityChipModel.Shown { StatusBarNotifChips.assertInNewMode() - val icon = OngoingActivityChipModel.ChipIcon.StatusBarView(this.statusBarChipIconView) - // TODO(b/364653005): Use the notification color if applicable. - val colors = ColorsModel.Themed + val icon = + if (this.statusBarChipIconView != null) { + StatusBarConnectedDisplays.assertInLegacyMode() + OngoingActivityChipModel.ChipIcon.StatusBarView(this.statusBarChipIconView) + } else { + StatusBarConnectedDisplays.assertInNewMode() + OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(this.key) + } + val colors = + ColorsModel.Custom( + backgroundColorInt = this.promotedContent.colors.backgroundColor, + primaryTextColorInt = this.promotedContent.colors.primaryTextColor, + ) val onClickListener = View.OnClickListener { // The notification pipeline needs everything to run on the main thread, so keep diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt index 730784a46001..cf69d401df60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt @@ -32,11 +32,13 @@ import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifCh import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.view.ChipChronometer +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore /** Binder for ongoing activity chip views. */ object OngoingActivityChipBinder { /** Binds the given [chipModel] data to the given [chipView]. */ - fun bind(chipModel: OngoingActivityChipModel, chipView: View) { + fun bind(chipModel: OngoingActivityChipModel, chipView: View, iconViewStore: IconViewStore?) { val chipContext = chipView.context val chipDefaultIconView: ImageView = chipView.requireViewById(R.id.ongoing_activity_chip_icon) @@ -51,7 +53,7 @@ object OngoingActivityChipBinder { when (chipModel) { is OngoingActivityChipModel.Shown -> { // Data - setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView) + setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView, iconViewStore) setChipMainContent(chipModel, chipTextView, chipTimeView, chipShortTimeDeltaView) chipView.setOnClickListener(chipModel.onClickListener) updateChipPadding( @@ -85,6 +87,7 @@ object OngoingActivityChipBinder { chipModel: OngoingActivityChipModel.Shown, backgroundView: ChipBackgroundContainer, defaultIconView: ImageView, + iconViewStore: IconViewStore?, ) { // Always remove any previously set custom icon. If we have a new custom icon, we'll re-add // it. @@ -108,38 +111,62 @@ object OngoingActivityChipBinder { defaultIconView.untintView() } is OngoingActivityChipModel.ChipIcon.StatusBarView -> { - // Hide the default icon since we'll show this custom icon instead. - defaultIconView.visibility = View.GONE - - // Add the new custom icon: - // 1. Set up the right visual params. - val iconView = icon.impl - with(iconView) { - id = CUSTOM_ICON_VIEW_ID - // TODO(b/354930838): Update the content description to not include "phone" and - // maybe include the app name. - contentDescription = - context.resources.getString(R.string.ongoing_phone_call_content_description) - tintView(iconTint) + StatusBarConnectedDisplays.assertInLegacyMode() + setStatusBarIconView(defaultIconView, icon.impl, iconTint, backgroundView) + } + is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon -> { + StatusBarConnectedDisplays.assertInNewMode() + val iconView = fetchStatusBarIconView(iconViewStore, icon) + if (iconView == null) { + // This means that the notification key doesn't exist anymore. + return } + setStatusBarIconView(defaultIconView, iconView, iconTint, backgroundView) + } + } + } - // 2. If we just reinflated the view, we may need to detach the icon view from the - // old chip before we reattach it to the new one. - // See also: NotificationIconContainerViewBinder#bindIcons. - val currentParent = iconView.parent as? ViewGroup - if (currentParent != null && currentParent != backgroundView) { - currentParent.removeView(iconView) - currentParent.removeTransientView(iconView) - } + private fun fetchStatusBarIconView( + iconViewStore: IconViewStore?, + icon: OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon, + ): StatusBarIconView? { + StatusBarConnectedDisplays.assertInNewMode() + if (iconViewStore == null) { + throw IllegalStateException("Store should always be non-null when flag is enabled.") + } + return iconViewStore.iconView(icon.notificationKey) + } - // 3: Add the icon as the starting view. - backgroundView.addView( - iconView, - /* index= */ 0, - generateCustomIconLayoutParams(iconView), - ) - } + private fun setStatusBarIconView( + defaultIconView: ImageView, + iconView: StatusBarIconView, + iconTint: Int, + backgroundView: ChipBackgroundContainer, + ) { + // Hide the default icon since we'll show this custom icon instead. + defaultIconView.visibility = View.GONE + + // 1. Set up the right visual params. + with(iconView) { + id = CUSTOM_ICON_VIEW_ID + // TODO(b/354930838): Update the content description to not include "phone" and maybe + // include the app name. + contentDescription = + context.resources.getString(R.string.ongoing_phone_call_content_description) + tintView(iconTint) + } + + // 2. If we just reinflated the view, we may need to detach the icon view from the old chip + // before we reattach it to the new one. + // See also: NotificationIconContainerViewBinder#bindIcons. + val currentParent = iconView.parent as? ViewGroup + if (currentParent != null && currentParent != backgroundView) { + currentParent.removeView(iconView) + currentParent.removeTransientView(iconView) } + + // 3: Add the icon as the starting view. + backgroundView.addView(iconView, /* index= */ 0, generateCustomIconLayoutParams(iconView)) } private fun View.getCustomIconView(): StatusBarIconView? { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt index 4b0fc5ab6059..efedf41e4684 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt @@ -40,21 +40,25 @@ sealed interface ColorsModel { } /** - * The chip should have the given background color, and text color that matches dark/light - * theme. + * The chip should have the given background color and primary text color. + * + * If [primaryTextColorInt] is null, the text color will match the current UI mode (light/dark). */ - data class Custom(val backgroundColorInt: Int) : ColorsModel { + data class Custom(val backgroundColorInt: Int, val primaryTextColorInt: Int? = null) : + ColorsModel { override fun background(context: Context): ColorStateList = ColorStateList.valueOf(backgroundColorInt) - // TODO(b/361346412): When dark theme changes, the chip should automatically re-render with + // TODO(b/361346412): When UI mode changes, the chip should automatically re-render with // the right text color. Right now, it has the right text color when the chip is first - // created but the color doesn't update if dark theme changes. - override fun text(context: Context) = - Utils.getColorAttrDefaultColor( - context, - com.android.internal.R.attr.materialColorOnSurface, - ) + // created but the color doesn't update if UI mode changes. + override fun text(context: Context): Int { + return primaryTextColorInt + ?: Utils.getColorAttrDefaultColor( + context, + com.android.internal.R.color.materialColorOnSurface, + ) + } } /** The chip should have a red background with white text. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt index cf07af1fc5dd..2dce4e38b803 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt @@ -21,6 +21,7 @@ import com.android.systemui.Flags import com.android.systemui.common.shared.model.Icon import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays /** Model representing the display of an ongoing activity as a chip in the status bar. */ sealed class OngoingActivityChipModel { @@ -132,6 +133,17 @@ sealed class OngoingActivityChipModel { "OngoingActivityChipModel.ChipIcon.StatusBarView created even though " + "Flags.statusBarCallChipNotificationIcon is not enabled" } + StatusBarConnectedDisplays.assertInLegacyMode() + } + } + + /** + * The icon is a custom icon, which is set on a notification, and can be looked up using the + * provided [notificationKey]. The icon was likely created by an external app. + */ + data class StatusBarNotificationIcon(val notificationKey: String) : ChipIcon { + init { + StatusBarConnectedDisplays.assertInNewMode() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt index 280d66bcb827..6cf2c73a7138 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt @@ -18,9 +18,9 @@ package com.android.systemui.statusbar.data.repository import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR import com.android.systemui.CoreStartable -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository import com.android.systemui.display.data.repository.PerDisplayStore @@ -74,7 +74,7 @@ constructor( @SysUISingleton class SingleDisplayStatusBarConfigurationControllerStore @Inject -constructor(@GlobalConfig globalConfigurationController: ConfigurationController) : +constructor(@Main globalConfigurationController: ConfigurationController) : StatusBarConfigurationControllerStore, PerDisplayStore<StatusBarConfigurationController> by SingleDisplayStore( globalConfigurationController as StatusBarConfigurationController 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/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java index a0515ca92cdd..d25889820629 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java @@ -39,7 +39,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import com.android.settingslib.Utils; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.ColorUpdateLogger; import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; @@ -457,8 +456,8 @@ public class FooterView extends StackScrollerDecorView { */ public void updateColors() { Resources.Theme theme = mContext.getTheme(); - final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorOnSurface); + final @ColorInt int onSurface = mContext.getColor( + com.android.internal.R.color.materialColorOnSurface); // Same resource, separate drawables to prevent touch effects from showing on the wrong // button. final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background); @@ -467,8 +466,8 @@ public class FooterView extends StackScrollerDecorView { ? theme.getDrawable(R.drawable.notif_footer_btn_background) : null; final @ColorInt int scHigh; if (!notificationFooterBackgroundTintOptimization()) { - scHigh = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorSurfaceContainerHigh); + scHigh = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); if (scHigh != 0) { final ColorFilter bgColorFilter = new PorterDuffColorFilter(scHigh, SRC_ATOP); clearAllBg.setColorFilter(bgColorFilter); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java index 0b188afa1c35..d0c02f77f382 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java @@ -183,7 +183,7 @@ public class HeadsUpManagerImpl @Inject public HeadsUpManagerImpl( - @NonNull final Context context, + @NonNull @ShadeDisplayAware final Context context, HeadsUpManagerLogger logger, StatusBarStateController statusBarStateController, KeyguardBypassController bypassController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt index 0f19d7288f6f..9dc3ed29570b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt @@ -18,13 +18,14 @@ package com.android.systemui.statusbar.notification.icon import android.app.Notification import android.content.Context +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.contentDescForNotification import javax.inject.Inject /** Testable wrapper around Context. */ -class IconBuilder @Inject constructor(private val context: Context) { +class IconBuilder @Inject constructor(@Main private val context: Context) { @JvmOverloads fun createIconView( entry: NotificationEntry, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt index 98ce163b81ca..b56a838a80a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt @@ -162,7 +162,9 @@ constructor( val sbIcon = iconBuilder.createIconView(entry) sbIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE val sbChipIcon: StatusBarIconView? - if (Flags.statusBarCallChipNotificationIcon()) { + if ( + Flags.statusBarCallChipNotificationIcon() && !StatusBarConnectedDisplays.isEnabled + ) { sbChipIcon = iconBuilder.createIconView(entry) sbChipIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt index 6dbb71463602..643ee249e75e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder import android.graphics.Color -import android.graphics.Rect import android.util.Log import android.view.View import android.view.ViewGroup @@ -53,7 +52,6 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.stateIn /** Binds a view-model to a [NotificationIconContainer]. */ @@ -71,10 +69,7 @@ object NotificationIconContainerViewBinder { launch { val contrastColorUtil = ContrastColorUtil.getInstance(view.context) val iconColors: StateFlow<NotificationIconColors> = - viewModel - .iconColors(displayId) - .mapNotNull { it.iconColors(view.viewBounds) } - .stateIn(this) + viewModel.iconColors(displayId).stateIn(this) viewModel.icons.bindIcons( logTag = "statusbar", view = view, @@ -374,18 +369,6 @@ fun NotifCollection.iconViewStoreBy(block: (IconPack) -> StatusBarIconView?) = getEntry(key)?.icons?.let(block) } -private val View.viewBounds: Rect - get() { - val tmpArray = intArrayOf(0, 0) - getLocationOnScreen(tmpArray) - return Rect( - /* left = */ tmpArray[0], - /* top = */ tmpArray[1], - /* right = */ left + width, - /* bottom = */ top + height, - ) - } - private suspend inline fun <T> Flow<T>.collectTracingEach( tag: String, crossinline collector: (T) -> Unit, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt index 83f56a092bc6..124bd2eece36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/StatusBarIconViewBinder.kt @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.notification.icon.ui.viewbinder -import android.graphics.Rect -import android.view.View import com.android.app.tracing.traceSection import com.android.internal.util.ContrastColorUtil import com.android.systemui.res.R @@ -25,6 +23,7 @@ import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.StatusBarIconView.NO_COLOR import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconColors +import com.android.systemui.util.view.viewBoundsOnScreen import kotlinx.coroutines.flow.Flow object StatusBarIconViewBinder { @@ -60,25 +59,13 @@ object StatusBarIconViewBinder { val isPreL = java.lang.Boolean.TRUE == view.getTag(R.id.icon_is_pre_L) val isColorized = !isPreL || NotificationUtils.isGrayscale(view, contrastColorUtil) view.staticDrawableColor = - if (isColorized) colors.staticDrawableColor(view.viewBounds) else NO_COLOR + if (isColorized) colors.staticDrawableColor(view.viewBoundsOnScreen()) else NO_COLOR // Set the color for the overflow dot view.setDecorColor(colors.tint) } } } -private val View.viewBounds: Rect - get() { - val tmpArray = intArrayOf(0, 0) - getLocationOnScreen(tmpArray) - return Rect( - /* left = */ tmpArray[0], - /* top = */ tmpArray[1], - /* right = */ left + width, - /* bottom = */ top + height, - ) - } - private suspend inline fun <T> Flow<T>.collectTracingEach( tag: String, crossinline collector: (T) -> Unit, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt index 2365db451836..a9635dcd2bc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconColors.kt @@ -17,14 +17,6 @@ package com.android.systemui.statusbar.notification.icon.ui.viewmodel import android.graphics.Rect -/** - * Lookup the colors to use for the notification icons based on the bounds of the icon container. A - * result of `null` indicates that no color changes should be applied. - */ -fun interface NotificationIconColorLookup { - fun iconColors(viewBounds: Rect): NotificationIconColors? -} - /** Colors to apply to notification icons. */ interface NotificationIconColors { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt index f0b03065e637..2ba28a660116 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt @@ -68,18 +68,10 @@ constructor( .distinctUntilChanged() /** The colors with which to display the notification icons. */ - fun iconColors(displayId: Int): Flow<NotificationIconColorLookup> = + fun iconColors(displayId: Int): Flow<NotificationIconColors> = darkIconInteractor .darkState(displayId) - .map { (areas: Collection<Rect>, tint: Int) -> - NotificationIconColorLookup { viewBounds: Rect -> - if (DarkIconDispatcher.isInAreas(areas, viewBounds)) { - IconColorsImpl(tint, areas) - } else { - null - } - } - } + .map { (areas: Collection<Rect>, tint: Int) -> IconColorsImpl(tint, areas) } .flowOn(bgContext) .conflate() .distinctUntilChanged() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt index 38eaf27ad358..e122ca888f45 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt @@ -77,6 +77,13 @@ constructor( contentBuilder.text = notification.text() contentBuilder.skeletonLargeIcon = null // TODO + val colorsFromNotif = recoveredBuilder.getColors(/* header= */ false) + contentBuilder.colors = + PromotedNotificationContentModel.Colors( + backgroundColor = colorsFromNotif.backgroundColor, + primaryTextColor = colorsFromNotif.primaryTextColor, + ) + recoveredBuilder.style?.extractContent(contentBuilder) ?: run { contentBuilder.style = Style.Ineligible } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt index 41ee3b992c5a..0af40437828e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.promoted.shared.model import android.annotation.DrawableRes import android.graphics.drawable.Icon +import androidx.annotation.ColorInt import com.android.internal.widget.NotificationProgressModel import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi @@ -39,6 +40,7 @@ data class PromotedNotificationContentModel( val title: CharSequence?, val text: CharSequence?, val skeletonLargeIcon: Icon?, // TODO(b/377568176): Make into an IconModel. + val colors: Colors, val style: Style, // for CallStyle: @@ -61,6 +63,7 @@ data class PromotedNotificationContentModel( var text: CharSequence? = null var skeletonLargeIcon: Icon? = null var style: Style = Style.Ineligible + var colors: Colors = Colors(backgroundColor = 0, primaryTextColor = 0) // for CallStyle: var personIcon: Icon? = null @@ -83,6 +86,7 @@ data class PromotedNotificationContentModel( title = title, text = text, skeletonLargeIcon = skeletonLargeIcon, + colors = colors, style = style, personIcon = personIcon, personName = personName, @@ -102,6 +106,9 @@ data class PromotedNotificationContentModel( } } + /** The colors used to display the notification. */ + data class Colors(@ColorInt val backgroundColor: Int, @ColorInt val primaryTextColor: Int) + /** The promotion-eligible style of a notification, or [Style.Ineligible] if not. */ enum class Style { BigPicture, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 5c51adadfd82..b4092cd785bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -37,7 +37,6 @@ import android.view.animation.Interpolator; import com.android.app.animation.Interpolators; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor.Configuration; -import com.android.settingslib.Utils; import com.android.systemui.Gefingerpoken; import com.android.systemui.res.R; import com.android.systemui.shade.TouchLogger; @@ -123,8 +122,8 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void updateColors() { - mNormalColor = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorSurfaceContainerHigh); + mNormalColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); mTintedRippleColor = mContext.getColor( R.color.notification_ripple_tinted_color); mNormalRippleColor = mContext.getColor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt index a8d59d83d1e9..6bfc9f07ffc4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt @@ -40,6 +40,7 @@ import android.widget.TextView import com.android.internal.annotations.VisibleForTesting import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.shade.ShadeDisplayAware import javax.inject.Inject private const val TAG = "ChannelDialogController" @@ -58,11 +59,10 @@ private const val TAG = "ChannelDialogController" */ @SysUISingleton class ChannelEditorDialogController @Inject constructor( - c: Context, + @ShadeDisplayAware private val context: Context, private val noMan: INotificationManager, private val dialogBuilder: ChannelEditorDialog.Builder ) { - val context: Context = c.applicationContext private var prepared = false private lateinit var dialog: ChannelEditorDialog diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java index 61f4e96bf99a..5c4c253d1f98 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java @@ -21,7 +21,6 @@ import static android.app.Notification.COLOR_INVALID; import android.annotation.Nullable; import android.app.Flags; import android.content.Context; -import android.content.res.TypedArray; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -115,16 +114,9 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout } private void resolveThemeTextColors() { - try (TypedArray ta = mContext.getTheme().obtainStyledAttributes( - android.R.style.Theme_DeviceDefault_DayNight, new int[]{ - com.android.internal.R.attr.materialColorOnSurface, - com.android.internal.R.attr.materialColorOnSurfaceVariant - })) { - if (ta != null) { - mPrimaryTextColor = ta.getColor(0, mPrimaryTextColor); - mSecondaryTextColor = ta.getColor(1, mSecondaryTextColor); - } - } + mPrimaryTextColor = mContext.getColor(com.android.internal.R.color.materialColorOnSurface); + mSecondaryTextColor = mContext.getColor( + com.android.internal.R.color.materialColorOnSurfaceVariant); } public void bind(@Nullable CharSequence title, @Nullable CharSequence text, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index 34ef63944f14..e440d2728263 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -35,7 +35,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.util.ContrastColorUtil; -import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss; @@ -83,8 +82,8 @@ public class NotificationBackgroundView extends View implements Dumpable, R.color.notification_state_color_light); mDarkColoredStatefulColors = getResources().getColorStateList( R.color.notification_state_color_dark); - mNormalColor = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorSurfaceContainerHigh); + mNormalColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); mFocusOverlayStroke = getResources().getDimension(R.dimen.notification_focus_stroke_width); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index e141b7cf23ec..be9f60d4d5a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -43,7 +43,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; @@ -337,10 +336,7 @@ public class NotificationConversationInfo extends LinearLayout implements Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo); if (person == null) { person = mContext.getDrawable(R.drawable.ic_person).mutate(); - TypedArray ta = mContext.obtainStyledAttributes( - new int[]{com.android.internal.R.attr.materialColorPrimary}); - int colorPrimary = ta.getColor(0, 0); - ta.recycle(); + int colorPrimary = mContext.getColor(com.android.internal.R.color.materialColorPrimary); person.setTint(colorPrimary); } ImageView image = findViewById(R.id.conversation_icon); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt index f8aff69f0531..9d13ab53ec71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt @@ -21,7 +21,6 @@ import android.content.Context import android.graphics.drawable.AnimatedImageDrawable import android.view.View import android.view.ViewGroup -import android.view.ViewGroup.MarginLayoutParams import com.android.internal.widget.CachingIconView import com.android.internal.widget.ConversationLayout import com.android.internal.widget.MessagingGroup @@ -94,13 +93,6 @@ class NotificationConversationTemplateViewWrapper( // Reinspect the notification. Before the super call, because the super call also updates // the transformation types and we need to have our values set by then. resolveViews() - if (Flags.notificationsRedesignAppIcons() && row.isShowingAppIcon) { - // Override the margins to be 2dp instead of 4dp according to the new design if we're - // showing the app icon. - val lp = badgeIconView.layoutParams as MarginLayoutParams - lp.setMargins(2, 2, 2, 2) - badgeIconView.layoutParams = lp - } super.onContentUpdated(row) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 182fba34cafb..752a8abf055d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -38,7 +38,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.internal.util.ContrastColorUtil; import com.android.internal.widget.CachingIconView; -import com.android.settingslib.Utils; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.notification.FeedbackIcon; @@ -344,9 +343,8 @@ public abstract class NotificationViewWrapper implements TransformableView { if (customBackgroundColor != 0) { return customBackgroundColor; } - return Utils.getColorAttr(mView.getContext(), - com.android.internal.R.attr.materialColorSurfaceContainerHigh) - .getDefaultColor(); + return mView.getContext().getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); } public void setLegacy(boolean legacy) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index c8e18a8fe5ca..00cd8ce87738 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -16,11 +16,12 @@ package com.android.systemui.statusbar.notification.stack; +import static android.app.Flags.notificationsRedesignTemplates; + import android.app.Notification; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.Path.Direction; @@ -171,7 +172,9 @@ public class NotificationChildrenContainer extends ViewGroup R.dimen.notification_children_container_margin_top); mNotificationTopPadding = res.getDimensionPixelOffset( R.dimen.notification_children_container_top_padding); - mHeaderHeight = mNotificationHeaderMargin + mNotificationTopPadding; + mHeaderHeight = notificationsRedesignTemplates() + ? res.getDimensionPixelSize(R.dimen.notification_2025_header_height) + : mNotificationHeaderMargin + mNotificationTopPadding; mCollapsedBottomPadding = res.getDimensionPixelOffset( R.dimen.notification_children_collapsed_bottom_padding); mEnableShadowOnChildNotifications = @@ -1515,10 +1518,9 @@ public class NotificationChildrenContainer extends ViewGroup int color = mContainingNotification.getNotificationColor(); Resources.Theme theme = new ContextThemeWrapper(mContext, com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme(); - try (TypedArray ta = theme.obtainStyledAttributes( - new int[]{com.android.internal.R.attr.materialColorPrimary})) { - color = ta.getColor(0, color); - } + + color = mContext.getColor(com.android.internal.R.color.materialColorPrimary); + mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b9e38abf8ab2..072089981cc7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -83,7 +83,6 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.policy.SystemBarUtils; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.keyguard.KeyguardSliceView; -import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.ExpandHelper; @@ -2630,6 +2629,7 @@ public class NotificationStackScrollLayout private void updateContentHeight() { if (SceneContainerFlag.isEnabled()) { updateIntrinsicStackHeight(); + updateStackEndHeightAndStackHeight(mAmbientState.getExpansionFraction()); return; } @@ -4729,10 +4729,10 @@ public class NotificationStackScrollLayout * Update colors of section headers, shade footer, and empty shade views. */ void updateDecorViews() { - final @ColorInt int onSurface = Utils.getColorAttrDefaultColor( - mContext, com.android.internal.R.attr.materialColorOnSurface); - final @ColorInt int onSurfaceVariant = Utils.getColorAttrDefaultColor( - mContext, com.android.internal.R.attr.materialColorOnSurfaceVariant); + final @ColorInt int onSurface = mContext.getColor( + com.android.internal.R.color.materialColorOnSurface); + final @ColorInt int onSurfaceVariant = mContext.getColor( + com.android.internal.R.color.materialColorOnSurfaceVariant); ColorUpdateLogger colorUpdateLogger = ColorUpdateLogger.getInstance(); if (colorUpdateLogger != null) { 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/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt index bffcae99e7f6..b4561686b7b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt @@ -147,8 +147,7 @@ constructor( // The footer needs to be re-inflated every time the theme or the font size changes. configuration .inflateLayout<FooterView>( - if (NotifRedesignFooter.isEnabled) - R.layout.status_bar_notification_footer_redesign + if (NotifRedesignFooter.isEnabled) R.layout.notification_2025_footer else R.layout.status_bar_notification_footer, parentView, attachToRoot = 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/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index 7f95fb072ede..adfcb710da92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -53,6 +53,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QSPanelController; +import com.android.systemui.qs.flags.QsInCompose; import com.android.systemui.recents.ScreenPinningRequest; import com.android.systemui.res.R; import com.android.systemui.scene.shared.flag.SceneContainerFlag; @@ -209,10 +210,16 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba @Override public void clickTile(ComponentName tile) { - // Can't inject this because it changes with the QS fragment - QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); - if (qsPanelController != null) { - qsPanelController.clickTile(tile); + if (QsInCompose.isEnabled()) { + if (tile != null) { + mQSHost.clickTile(tile); + } + } else { + // Can't inject this because it changes with the QS fragment + QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); + if (qsPanelController != null) { + qsPanelController.clickTile(tile); + } } } 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/ConfigurationControllerStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt index 8f4279e80376..a324e6df8a33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerStartable.kt @@ -17,8 +17,8 @@ package com.android.systemui.statusbar.phone import com.android.systemui.CoreStartable -import com.android.systemui.common.ui.GlobalConfig import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener import javax.inject.Inject @@ -27,8 +27,8 @@ import javax.inject.Inject class ConfigurationControllerStartable @Inject constructor( - @GlobalConfig private val configurationController: ConfigurationController, - private val listeners: Set<@JvmSuppressWildcards ConfigurationListener> + @Main private val configurationController: ConfigurationController, + private val listeners: Set<@JvmSuppressWildcards ConfigurationListener>, ) : CoreStartable { override fun start() { listeners.forEach { configurationController.addCallback(it) } 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/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index e7c6fb46f984..324db79a4078 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -51,7 +51,6 @@ import com.android.internal.util.function.TriConsumer; import com.android.keyguard.BouncerPanelExpansionCalculator; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.settingslib.Utils; import com.android.systemui.Dumpable; import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants; @@ -82,9 +81,6 @@ import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; -import kotlinx.coroutines.CoroutineDispatcher; -import kotlinx.coroutines.ExperimentalCoroutinesApi; - import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -93,6 +89,9 @@ import java.util.function.Consumer; import javax.inject.Inject; +import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.ExperimentalCoroutinesApi; + /** * Controls both the scrim behind the notifications and in front of the notifications (when a * security method gets shown). @@ -1532,17 +1531,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump private void updateThemeColors() { if (mScrimBehind == null) return; - int background = Utils.getColorAttr(mScrimBehind.getContext(), - com.android.internal.R.attr.materialColorSurfaceDim).getDefaultColor(); - int accent = Utils.getColorAttr(mScrimBehind.getContext(), - com.android.internal.R.attr.materialColorPrimary).getDefaultColor(); + int background = mScrimBehind.getContext().getColor( + com.android.internal.R.color.materialColorSurfaceDim); + int accent = mScrimBehind.getContext().getColor( + com.android.internal.R.color.materialColorPrimary); mColors.setMainColor(background); mColors.setSecondaryColor(accent); final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background); mColors.setSupportsDarkText(isBackgroundLight); - int surface = Utils.getColorAttr(mScrimBehind.getContext(), - com.android.internal.R.attr.materialColorSurface).getDefaultColor(); + int surface = mScrimBehind.getContext().getColor( + com.android.internal.R.color.materialColorSurface); for (ScrimState state : ScrimState.values()) { state.setSurfaceColor(surface); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java index b9cba9903466..d0d0b5c402e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java @@ -29,7 +29,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.settingslib.Utils; import com.android.systemui.res.R; import com.android.wm.shell.shared.animation.Interpolators; @@ -51,8 +50,8 @@ public class TapAgainView extends TextView { } void updateColor() { - final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext, - com.android.internal.R.attr.materialColorOnSurface); + final @ColorInt int onSurface = mContext.getColor( + com.android.internal.R.color.materialColorOnSurface); setTextColor(onSurface); setBackground(getResources().getDrawable(R.drawable.rounded_bg_full, mContext.getTheme())); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java index e4768e83f7d0..724ba8cab352 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java @@ -377,6 +377,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mCarrierConfigTracker.addDefaultDataSubscriptionChangedListener(mDefaultDataListener); mHomeStatusBarViewBinder.bind( + view.getContext().getDisplayId(), mStatusBar, mHomeStatusBarViewModel, /* systemEventChipAnimateIn */ null, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index 216630409160..c57cede754d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -260,6 +260,7 @@ constructor( startTimeMs = currentInfo.callStartTime, notificationIconView = icon, intent = currentInfo.intent, + notificationKey = currentInfo.key, ) } else { return OngoingCallModel.NoCall diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt index 1f7bd1418543..4b71c0268f11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt @@ -90,6 +90,7 @@ class OngoingCallInteractor @Inject constructor( startTimeMs = model.whenTime, notificationIconView = model.statusBarChipIconView, intent = model.contentIntent, + notificationKey = model.key, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt index c2c91b27d074..1a5dcc16f3db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt @@ -46,5 +46,6 @@ sealed interface OngoingCallModel { val startTimeMs: Long, val notificationIconView: StatusBarIconView?, val intent: PendingIntent?, + val notificationKey: String, ) : OngoingCallModel } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileContentDescriptionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileContentDescriptionViewBinder.kt new file mode 100644 index 000000000000..c720b1df1e62 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileContentDescriptionViewBinder.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.ui.binder + +import android.view.View +import com.android.systemui.statusbar.pipeline.mobile.ui.model.MobileContentDescription + +object MobileContentDescriptionViewBinder { + fun bind(contentDescription: MobileContentDescription?, view: View) { + view.contentDescription = + when (contentDescription) { + null -> null + else -> contentDescription.loadContentDescription(view.context) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt index 31d349eb4cca..788f041b38c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt @@ -29,9 +29,9 @@ import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.graph.SignalDrawable import com.android.systemui.Flags.statusBarStaticInoutIndicators -import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.DarkIconDispatcher @@ -48,12 +48,8 @@ import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarViewBin import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.distinctUntilChanged -import com.android.app.tracing.coroutines.launchTraced as launch -private data class Colors( - @ColorInt val tint: Int, - @ColorInt val contrast: Int, -) +private data class Colors(@ColorInt val tint: Int, @ColorInt val contrast: Int) object MobileIconBinder { /** Binds the view to the view-model, continuing to update the former based on the latter */ @@ -87,7 +83,7 @@ object MobileIconBinder { MutableStateFlow( Colors( tint = DarkIconDispatcher.DEFAULT_ICON_TINT, - contrast = DarkIconDispatcher.DEFAULT_INVERSE_ICON_TINT + contrast = DarkIconDispatcher.DEFAULT_INVERSE_ICON_TINT, ) ) val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor) @@ -105,7 +101,7 @@ object MobileIconBinder { viewModel.verboseLogger?.logBinderReceivedVisibility( view, viewModel.subscriptionId, - isVisible + isVisible, ) view.isVisible = isVisible // [StatusIconContainer] can get out of sync sometimes. Make sure to @@ -152,7 +148,7 @@ object MobileIconBinder { launch { viewModel.contentDescription.distinctUntilChanged().collect { - ContentDescriptionViewBinder.bind(it, view) + MobileContentDescriptionViewBinder.bind(it, view) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/MobileContentDescription.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/MobileContentDescription.kt new file mode 100644 index 000000000000..84fa07379a49 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/MobileContentDescription.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.pipeline.mobile.ui.model + +import android.annotation.StringRes +import android.content.Context +import com.android.systemui.res.R + +sealed interface MobileContentDescription { + fun loadContentDescription(context: Context): String + + /** + * Content description for cellular parameterizes the [networkName] which comes from the system + */ + data class Cellular(val networkName: String, @StringRes val levelDescriptionRes: Int) : + MobileContentDescription { + override fun loadContentDescription(context: Context): String = + context.getString( + R.string.accessibility_phone_string_format, + networkName, + context.getString(levelDescriptionRes), + ) + } + + data class SatelliteContentDescription(@StringRes val resId: Int) : MobileContentDescription { + override fun loadContentDescription(context: Context): String = + context.getString(this.resId) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 103b0e3a6f27..0bd3426712bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel -import com.android.settingslib.AccessibilityContentDescriptions import com.android.systemui.Flags.statusBarStaticInoutIndicators import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon @@ -28,6 +27,7 @@ import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.Airpla import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel +import com.android.systemui.statusbar.pipeline.mobile.ui.model.MobileContentDescription import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import kotlinx.coroutines.CoroutineScope @@ -50,7 +50,7 @@ interface MobileIconViewModelCommon { /** True if this view should be visible at all. */ val isVisible: StateFlow<Boolean> val icon: Flow<SignalIconModel> - val contentDescription: Flow<ContentDescription?> + val contentDescription: Flow<MobileContentDescription?> val roaming: Flow<Boolean> /** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */ val networkTypeIcon: Flow<Icon.Resource?> @@ -95,10 +95,7 @@ class MobileIconViewModel( } private val satelliteProvider by lazy { - CarrierBasedSatelliteViewModelImpl( - subscriptionId, - iconInteractor, - ) + CarrierBasedSatelliteViewModelImpl(subscriptionId, iconInteractor) } /** @@ -123,7 +120,7 @@ class MobileIconViewModel( override val icon: Flow<SignalIconModel> = vmProvider.flatMapLatest { it.icon } - override val contentDescription: Flow<ContentDescription?> = + override val contentDescription: Flow<MobileContentDescription?> = vmProvider.flatMapLatest { it.contentDescription } override val roaming: Flow<Boolean> = vmProvider.flatMapLatest { it.roaming } @@ -154,8 +151,7 @@ private class CarrierBasedSatelliteViewModelImpl( override val isVisible: StateFlow<Boolean> = MutableStateFlow(true) override val icon: Flow<SignalIconModel> = interactor.signalLevelIcon - override val contentDescription: Flow<ContentDescription> = - MutableStateFlow(ContentDescription.Loaded("")) + override val contentDescription: Flow<MobileContentDescription?> = MutableStateFlow(null) /** These fields are not used for satellite icons currently */ override val roaming: Flow<Boolean> = flowOf(false) @@ -206,27 +202,42 @@ private class CellularIconViewModel( override val icon: Flow<SignalIconModel> = iconInteractor.signalLevelIcon - override val contentDescription: Flow<ContentDescription?> = - iconInteractor.signalLevelIcon - .map { - // We expect the signal icon to be cellular here since this is the cellular vm - if (it !is SignalIconModel.Cellular) { - null - } else { - val resId = - AccessibilityContentDescriptions.getDescriptionForLevel( - it.level, - it.numberOfLevels + override val contentDescription: Flow<MobileContentDescription?> = + combine(iconInteractor.signalLevelIcon, iconInteractor.networkName) { icon, nameModel -> + when (icon) { + is SignalIconModel.Cellular -> + MobileContentDescription.Cellular( + nameModel.name, + icon.levelDescriptionRes(), ) - if (resId != 0) { - ContentDescription.Resource(resId) - } else { - null - } + else -> null } } .stateIn(scope, SharingStarted.WhileSubscribed(), null) + private fun SignalIconModel.Cellular.levelDescriptionRes() = + when (level) { + 0 -> R.string.accessibility_no_signal + 1 -> R.string.accessibility_one_bar + 2 -> R.string.accessibility_two_bars + 3 -> R.string.accessibility_three_bars + 4 -> { + if (numberOfLevels == 6) { + R.string.accessibility_four_bars + } else { + R.string.accessibility_signal_full + } + } + 5 -> { + if (numberOfLevels == 6) { + R.string.accessibility_signal_full + } else { + R.string.accessibility_no_signal + } + } + else -> R.string.accessibility_no_signal + } + private val showNetworkTypeIcon: Flow<Boolean> = combine( iconInteractor.isDataConnected, @@ -248,10 +259,9 @@ private class CellularIconViewModel( .stateIn(scope, SharingStarted.WhileSubscribed(), false) override val networkTypeIcon: Flow<Icon.Resource?> = - combine( - iconInteractor.networkTypeIconGroup, - showNetworkTypeIcon, - ) { networkTypeIconGroup, shouldShow -> + combine(iconInteractor.networkTypeIconGroup, showNetworkTypeIcon) { + networkTypeIconGroup, + shouldShow -> val desc = if (networkTypeIconGroup.contentDescription != 0) ContentDescription.Resource(networkTypeIconGroup.contentDescription) 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/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt index 72df02714d43..d9b2bd1d66c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt @@ -20,9 +20,9 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.view.View import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.app.animation.Interpolators -import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.repeatWhenAttached @@ -31,16 +31,19 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingIn import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingOut import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.RunningChipAnim +import com.android.systemui.statusbar.notification.icon.ui.viewbinder.ConnectedDisplaysStatusBarNotificationIconViewStore import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel.VisibilityModel import javax.inject.Inject +import kotlinx.coroutines.launch /** * Interface to assist with binding the [CollapsedStatusBarFragment] to [HomeStatusBarViewModel]. @@ -56,6 +59,7 @@ interface HomeStatusBarViewBinder { * to support the chip animations. */ fun bind( + displayId: Int, view: View, viewModel: HomeStatusBarViewModel, systemEventChipAnimateIn: ((View) -> Unit)?, @@ -65,8 +69,13 @@ interface HomeStatusBarViewBinder { } @SysUISingleton -class HomeStatusBarViewBinderImpl @Inject constructor() : HomeStatusBarViewBinder { +class HomeStatusBarViewBinderImpl +@Inject +constructor( + private val viewStoreFactory: ConnectedDisplaysStatusBarNotificationIconViewStore.Factory +) : HomeStatusBarViewBinder { override fun bind( + displayId: Int, view: View, viewModel: HomeStatusBarViewModel, systemEventChipAnimateIn: ((View) -> Unit)?, @@ -75,6 +84,14 @@ class HomeStatusBarViewBinderImpl @Inject constructor() : HomeStatusBarViewBinde ) { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { + val iconViewStore = + if (StatusBarConnectedDisplays.isEnabled) { + viewStoreFactory.create(displayId).also { + lifecycleScope.launch { it.activate() } + } + } else { + null + } launch { viewModel.isTransitioningFromLockscreenToOccluded.collect { listener.onStatusBarVisibilityMaybeChanged() @@ -102,7 +119,11 @@ class HomeStatusBarViewBinderImpl @Inject constructor() : HomeStatusBarViewBinde view.requireViewById(R.id.ongoing_activity_chip_primary) launch { viewModel.primaryOngoingActivityChip.collect { primaryChipModel -> - OngoingActivityChipBinder.bind(primaryChipModel, primaryChipView) + OngoingActivityChipBinder.bind( + primaryChipModel, + primaryChipView, + iconViewStore, + ) if (StatusBarRootModernization.isEnabled) { when (primaryChipModel) { is OngoingActivityChipModel.Shown -> @@ -142,10 +163,18 @@ class HomeStatusBarViewBinderImpl @Inject constructor() : HomeStatusBarViewBinde view.requireViewById(R.id.ongoing_activity_chip_secondary) launch { viewModel.ongoingActivityChips.collect { chips -> - OngoingActivityChipBinder.bind(chips.primary, primaryChipView) + OngoingActivityChipBinder.bind( + chips.primary, + primaryChipView, + iconViewStore, + ) // TODO(b/364653005): Don't show the secondary chip if there isn't // enough space for it. - OngoingActivityChipBinder.bind(chips.secondary, secondaryChipView) + OngoingActivityChipBinder.bind( + chips.secondary, + secondaryChipView, + iconViewStore, + ) if (StatusBarRootModernization.isEnabled) { primaryChipView.adjustVisibility(chips.primary.toVisibilityModel()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt index 812e0eb0908f..5614d82c2e4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt @@ -176,6 +176,7 @@ fun StatusBarRoot( // This binder handles everything else scope.launch { statusBarViewBinder.bind( + context.displayId, phoneStatusBarView, statusBarViewModel, eventAnimationInteractor::animateStatusBarContentForChipEnter, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 16d5f8d30593..2b0bf1a3d343 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -24,7 +24,6 @@ import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.ColorStateList; -import android.content.res.TypedArray; import android.graphics.BlendMode; import android.graphics.Color; import android.graphics.PorterDuff; @@ -174,11 +173,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mTextWatcher = new SendButtonTextWatcher(); mEditorActionHandler = new EditorActionHandler(); mUiEventLogger = Dependency.get(UiEventLogger.class); - TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorSurfaceDim, - }); - mLastBackgroundColor = ta.getColor(0, 0); - ta.recycle(); + mLastBackgroundColor = getContext().getColor( + com.android.internal.R.color.materialColorSurfaceDim); } // TODO(b/193539698): move to Controller, since we're just directly accessing a system service @@ -229,13 +225,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene textColor = mContext.getColorStateList(R.color.remote_input_text); hintColor = mContext.getColor(R.color.remote_input_hint); deleteFgColor = textColor.getDefaultColor(); - try (TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{ - com.android.internal.R.attr.materialColorSurfaceDim, - com.android.internal.R.attr.materialColorSurfaceVariant - })) { - editBgColor = ta.getColor(0, backgroundColor); - deleteBgColor = ta.getColor(1, Color.GRAY); - } + editBgColor = getContext().getColor( + com.android.internal.R.color.materialColorSurfaceDim); + deleteBgColor = getContext().getColor( + com.android.internal.R.color.materialColorSurfaceVariant); } mEditText.setTextColor(textColor); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java index 9187e3c43380..d1e807f18196 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java @@ -23,7 +23,6 @@ import android.os.UserManager; import com.android.internal.R; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.settingslib.notification.modes.ZenIconLoader; -import com.android.systemui.common.ui.GlobalConfig; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Main; @@ -111,7 +110,7 @@ public interface StatusBarPolicyModule { * wrong updates in case of secondary displays. */ @Binds - ConfigurationController bindConfigurationController(@GlobalConfig ConfigurationController impl); + ConfigurationController bindConfigurationController(@Main ConfigurationController impl); /** */ @Binds @@ -189,14 +188,14 @@ public interface StatusBarPolicyModule { /** */ @Binds @SysUISingleton - @GlobalConfig + @Main ConfigurationForwarder provideGlobalConfigurationForwarder( - @GlobalConfig ConfigurationController configurationController); + @Main ConfigurationController configurationController); /** */ @Provides @SysUISingleton - @GlobalConfig + @Main static ConfigurationController provideGlobalConfigurationController( @Application Context context, ConfigurationControllerImpl.Factory factory) { return factory.create(context); diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt index 7475388e80c2..0a10b440644d 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarInfo.kt @@ -18,7 +18,7 @@ package com.android.systemui.temporarydisplay.chipbar import android.os.VibrationEffect import android.view.View -import androidx.annotation.AttrRes +import androidx.annotation.ColorRes import com.android.internal.logging.InstanceId import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.TintedIcon @@ -52,8 +52,8 @@ data class ChipbarInfo( ) : TemporaryViewInfo() { companion object { // LINT.IfChange - @AttrRes val DEFAULT_ICON_TINT = com.android.internal.R.attr.materialColorOnSecondaryFixed - // LINT.ThenChange(systemui/res/layout/chipbar.xml) + @ColorRes val DEFAULT_ICON_TINT = com.android.internal.R.color.materialColorOnSecondaryFixed + // LINT.ThenChange(/packages/SystemUI/res/layout/chipbar.xml) } } diff --git a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt index 6160b00379ef..5b48c1ff628c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt +++ b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt @@ -35,27 +35,21 @@ class ViewUtil @Inject constructor() { fun touchIsWithinView(view: View, x: Float, y: Float): Boolean { val left = view.locationOnScreen[0] val top = view.locationOnScreen[1] - return left <= x && - x <= left + view.width && - top <= y && - y <= top + view.height + return left <= x && x <= left + view.width && top <= y && y <= top + view.height } - /** - * Sets [outRect] to be the view's location within its window. - */ - fun setRectToViewWindowLocation(view: View, outRect: Rect) { - val locInWindow = IntArray(2) - view.getLocationInWindow(locInWindow) - - val x = locInWindow[0] - val y = locInWindow[1] - - outRect.set( - x, - y, - x + view.width, - y + view.height, - ) - } + /** Sets [outRect] to be the view's location within its window. */ + fun setRectToViewWindowLocation(view: View, outRect: Rect) = view.viewBoundsOnScreen(outRect) +} + +fun View.viewBoundsOnScreen(outRect: Rect) { + val locInWindow = IntArray(2) + getLocationInWindow(locInWindow) + + val x = locInWindow[0] + val y = locInWindow[1] + + outRect.set(x, y, x + width, y + height) } + +fun View.viewBoundsOnScreen(): Rect = Rect().also { viewBoundsOnScreen(it) } 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..f04fb2c3b8d5 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 @@ -30,10 +30,10 @@ import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce import com.android.internal.R as internalR -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 +42,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 +72,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 +109,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 +123,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 +160,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 +192,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 +220,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) } @@ -234,15 +293,11 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { } if (isSelected && !isAnimated) { setBackgroundResource(R.drawable.volume_drawer_selection_bg) - setColorFilter( - Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnPrimary) - ) + setColorFilter(context.getColor(internalR.color.materialColorOnPrimary)) background = background.mutate() } else if (!isAnimated) { setBackgroundResource(R.drawable.volume_ringer_item_bg) - setColorFilter( - Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnSurface) - ) + setColorFilter(context.getColor(internalR.color.materialColorOnSurface)) background = background.mutate() } setOnClickListener { @@ -366,6 +421,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 +432,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 +463,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/RingerButtonUiModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerButtonUiModel.kt index 3c465674ebb5..832f1c3471d6 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerButtonUiModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/RingerButtonUiModel.kt @@ -31,30 +31,20 @@ data class RingerButtonUiModel( companion object { fun getUnselectedButton(context: Context): RingerButtonUiModel { return RingerButtonUiModel( - tintColor = - Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnSurface), - backgroundColor = - Utils.getColorAttrDefaultColor( - context, - internalR.attr.materialColorSurfaceContainerHighest, - ), - cornerRadius = - context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_background_square_corner_radius - ), + tintColor = context.getColor(internalR.color.materialColorOnSurface), + backgroundColor = context.getColor( + internalR.color.materialColorSurfaceContainerHighest), + cornerRadius = context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_background_square_corner_radius), ) } fun getSelectedButton(context: Context): RingerButtonUiModel { return RingerButtonUiModel( - tintColor = - Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorOnPrimary), - backgroundColor = - Utils.getColorAttrDefaultColor(context, internalR.attr.materialColorPrimary), - cornerRadius = - context.resources.getDimensionPixelSize( - R.dimen.volume_dialog_ringer_selected_button_background_radius - ), + tintColor = context.getColor(internalR.color.materialColorOnPrimary), + backgroundColor = context.getColor(internalR.color.materialColorPrimary), + cornerRadius = context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_ringer_selected_button_background_radius), ) } } 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/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt index 02747d7e6996..6c4a853b42ad 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt @@ -80,10 +80,10 @@ constructor( label = label, labelColor = if (Flags.volumeRedesign()) { - Color.Attribute(com.android.internal.R.attr.materialColorOnSurface) + Color.Resource(com.android.internal.R.color.materialColorOnSurface) } else { - Color.Attribute( - com.android.internal.R.attr.materialColorOnSurfaceVariant + Color.Resource( + com.android.internal.R.color.materialColorOnSurfaceVariant ) }, deviceName = @@ -96,10 +96,10 @@ constructor( }, deviceNameColor = if (mediaOutputModel.canOpenAudioSwitcher) { - Color.Attribute(com.android.internal.R.attr.materialColorOnSurface) + Color.Resource(com.android.internal.R.color.materialColorOnSurface) } else { - Color.Attribute( - com.android.internal.R.attr.materialColorOnSurfaceVariant + Color.Resource( + com.android.internal.R.color.materialColorOnSurfaceVariant ) }, ) @@ -126,32 +126,32 @@ constructor( iconColor = if (mediaOutputModel.canOpenAudioSwitcher) { if (Flags.volumeRedesign()) { - Color.Attribute( - com.android.internal.R.attr.materialColorOnPrimary + Color.Resource( + com.android.internal.R.color.materialColorOnPrimary ) } else { - Color.Attribute( - com.android.internal.R.attr.materialColorSurface + Color.Resource( + com.android.internal.R.color.materialColorSurface ) } } else { - Color.Attribute( - com.android.internal.R.attr.materialColorSurfaceContainerHighest + Color.Resource( + com.android.internal.R.color.materialColorSurfaceContainerHighest ) }, backgroundColor = if (mediaOutputModel.canOpenAudioSwitcher) { if (Flags.volumeRedesign()) { - Color.Attribute( - com.android.internal.R.attr.materialColorPrimary + Color.Resource( + com.android.internal.R.color.materialColorPrimary ) } else { - Color.Attribute( - com.android.internal.R.attr.materialColorSecondary + Color.Resource( + com.android.internal.R.color.materialColorSecondary ) } } else { - Color.Attribute(com.android.internal.R.attr.materialColorOutline) + Color.Resource(com.android.internal.R.color.materialColorOutline) }, ) } else { @@ -160,16 +160,16 @@ constructor( iconColor = if (mediaOutputModel.canOpenAudioSwitcher) { if (Flags.volumeRedesign()) { - Color.Attribute( - com.android.internal.R.attr.materialColorPrimary + Color.Resource( + com.android.internal.R.color.materialColorPrimary ) } else { - Color.Attribute( - com.android.internal.R.attr.materialColorOnSurfaceVariant + Color.Resource( + com.android.internal.R.color.materialColorOnSurfaceVariant ) } } else { - Color.Attribute(com.android.internal.R.attr.materialColorOutline) + Color.Resource(com.android.internal.R.color.materialColorOutline) }, backgroundColor = Color.Loaded(GraphicsColor.TRANSPARENT), ) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index f347d48c49cf..a41725f754df 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -529,6 +529,8 @@ class ClockEventControllerTest : SysuiTestCase() { fun listenForDnd_onDndChange_updatesClockZenMode() = testScope.runTest { underTest.listenForDnd(testScope.backgroundScope) + runCurrent() + clearInvocations(events) zenModeRepository.activateMode(dndModeId) runCurrent() @@ -537,7 +539,6 @@ class ClockEventControllerTest : SysuiTestCase() { .onZenDataChanged( eq(ZenData(ZenMode.IMPORTANT_INTERRUPTIONS, R.string::dnd_is_on.name)) ) - clearInvocations(events) zenModeRepository.deactivateMode(dndModeId) runCurrent() diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java index 50d0049dbcd7..dddaabb66022 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java @@ -26,10 +26,12 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.graphics.PointF; + import android.testing.TestableLooper; import android.view.View; import android.view.ViewPropertyAnimator; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.FlingAnimation; @@ -49,6 +51,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -69,13 +72,17 @@ public class MenuAnimationControllerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Mock + private AccessibilityManager mAccessibilityManager; + @Before public void setUp() throws Exception { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); final SecureSettings secureSettings = TestUtils.mockSecureSettings(); - final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, secureSettings); + final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, + secureSettings); mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance, secureSettings)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java index f4580c173579..400b3b388c31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java @@ -159,7 +159,8 @@ public class MenuViewLayerTest extends SysuiTestCase { new WindowMetrics(mDisplayBounds, fakeDisplayInsets(), /* density = */ 0.0f)); doReturn(mWindowMetrics).when(mStubWindowManager).getCurrentWindowMetrics(); - mMenuViewModel = new MenuViewModel(mSpyContext, mSecureSettings); + mMenuViewModel = new MenuViewModel( + mSpyContext, mStubAccessibilityManager, mSecureSettings); MenuViewAppearance menuViewAppearance = new MenuViewAppearance( mSpyContext, mStubWindowManager); mMenuView = spy( 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/media/controls/ui/viewmodel/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModelTest.kt index 4da7b2ac3700..e035a02ecf00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/viewmodel/SeekBarViewModelTest.kt @@ -64,9 +64,11 @@ public class SeekBarViewModelTest : SysuiTestCase() { override fun executeOnDiskIO(runnable: Runnable) { runnable.run() } + override fun postToMainThread(runnable: Runnable) { runnable.run() } + override fun isMainThread(): Boolean { return true } @@ -805,4 +807,32 @@ public class SeekBarViewModelTest : SysuiTestCase() { fakeExecutor.runAllReady() verify(mockController).unregisterCallback(any()) } + + @Test + fun positionUpdatedWhileStopped() { + // When playback is stopped at one position + val firstPosition = 200L + val state = + PlaybackState.Builder().run { + setState(PlaybackState.STATE_STOPPED, firstPosition, 1f) + build() + } + whenever(mockController.playbackState).thenReturn(state) + val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java) + viewModel.updateController(mockController) + verify(mockController).registerCallback(captor.capture()) + assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(firstPosition.toInt()) + + // And the state is updated with a new position + val secondPosition = 42L + val secondState = + PlaybackState.Builder().run { + setState(PlaybackState.STATE_STOPPED, secondPosition, 1f) + build() + } + captor.value.onPlaybackStateChanged(secondState) + + // THEN then elapsed time should be updated + assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(secondPosition.toInt()) + } } 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..fc720b836f72 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 @@ -84,7 +87,7 @@ class DragAndDropTest : SysuiTestCase() { } composeRule.waitForIdle() - listState.onStarted(TestEditTiles[0]) + listState.onStarted(TestEditTiles[0], DragType.Add) // Tile is being dragged, it should be replaced with a placeholder composeRule.onNodeWithContentDescription("tileA").assertDoesNotExist() @@ -110,8 +113,8 @@ class DragAndDropTest : SysuiTestCase() { } composeRule.waitForIdle() - listState.onStarted(TestEditTiles[0]) - listState.onMoved(1, false) + listState.onStarted(TestEditTiles[0], DragType.Add) + listState.onTargeting(1, false) listState.onDrop() // Available tiles should re-appear @@ -137,7 +140,7 @@ class DragAndDropTest : SysuiTestCase() { } composeRule.waitForIdle() - listState.onStarted(TestEditTiles[0]) + listState.onStarted(TestEditTiles[0], DragType.Add) listState.movedOutOfBounds() listState.onDrop() @@ -162,11 +165,11 @@ class DragAndDropTest : SysuiTestCase() { } composeRule.waitForIdle() - listState.onStarted(createEditTile("newTile")) + listState.onStarted(createEditTile("newTile"), DragType.Add) // Insert after tileD, which is at index 4 // [ a ] [ b ] [ c ] [ empty ] // [ tile d ] [ e ] - listState.onMoved(4, insertAfter = true) + listState.onTargeting(4, insertAfter = true) listState.onDrop() // Available tiles should re-appear @@ -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/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index e7fb470cfa76..c410111bc2e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -33,7 +33,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.compose.animation.scene.SceneKey import com.android.systemui.Flags -import com.android.systemui.Flags.FLAG_COMMUNAL_HUB_ON_MOBILE +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX import com.android.systemui.SysuiTestCase import com.android.systemui.ambient.touch.TouchHandler @@ -43,7 +43,9 @@ import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepositor import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.communal.domain.interactor.setCommunalAvailable +import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.ui.compose.CommunalContent import com.android.systemui.communal.ui.viewmodel.CommunalViewModel @@ -131,20 +133,26 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { underTest = GlanceableHubContainerController( communalInteractor, + communalSettingsInteractor, communalViewModel, keyguardInteractor, - kosmos.keyguardTransitionInteractor, + keyguardTransitionInteractor, shadeInteractor, powerManager, communalColors, ambientTouchComponentFactory, communalContent, - kosmos.sceneDataSourceDelegator, - kosmos.notificationStackScrollLayoutController, - kosmos.keyguardMediaController, - kosmos.lockscreenSmartspaceController, + sceneDataSourceDelegator, + notificationStackScrollLayoutController, + keyguardMediaController, + lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest"), ) + + // Make below last notification true by default or else touches will be ignored by + // default when the hub is not showing. + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(true) } testableLooper = TestableLooper.get(this) @@ -178,6 +186,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { underTest = GlanceableHubContainerController( communalInteractor, + kosmos.communalSettingsInteractor, communalViewModel, keyguardInteractor, kosmos.keyguardTransitionInteractor, @@ -207,6 +216,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { val underTest = GlanceableHubContainerController( communalInteractor, + kosmos.communalSettingsInteractor, communalViewModel, keyguardInteractor, kosmos.keyguardTransitionInteractor, @@ -231,6 +241,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { val underTest = GlanceableHubContainerController( communalInteractor, + kosmos.communalSettingsInteractor, communalViewModel, keyguardInteractor, kosmos.keyguardTransitionInteractor, @@ -631,7 +642,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } } - @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE) + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun onTouchEvent_shadeInteracting_movesNotDispatched() = with(kosmos) { @@ -688,7 +699,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } } - @DisableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE) + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun onTouchEvent_bouncerInteracting_movesNotDispatched() = with(kosmos) { @@ -721,11 +732,13 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } } - @EnableFlags(FLAG_COMMUNAL_HUB_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun onTouchEvent_onLockscreenAndGlanceableHubV2_touchIgnored() = with(kosmos) { testScope.runTest { + kosmos.setCommunalV2ConfigEnabled(true) + // On lockscreen. goToScene(CommunalScenes.Blank) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 11b19f95c1c0..99467cb11282 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -1275,6 +1275,37 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { } @Test + @EnableSceneContainer + public void testChildHeightUpdated_whenMaxDisplayedNotificationsSet_updatesStackHeight() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + int maxNotifs = 1; // any non-zero limit + float stackTop = 100; + float stackCutoff = 1100; + mStackScroller.setStackTop(stackTop); + mStackScroller.setStackCutoff(stackCutoff); + + // Given we have a limit on max displayed notifications + int stackHeightBeforeUpdate = 100; + when(mStackSizeCalculator.computeHeight(eq(mStackScroller), eq(maxNotifs), anyFloat())) + .thenReturn((float) stackHeightBeforeUpdate); + mStackScroller.setMaxDisplayedNotifications(maxNotifs); + + // And the stack heights are set + assertThat(mStackScroller.getIntrinsicStackHeight()).isEqualTo(stackHeightBeforeUpdate); + assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeightBeforeUpdate); + + // When a child changes its height + int stackHeightAfterUpdate = 300; + when(mStackSizeCalculator.computeHeight(eq(mStackScroller), eq(maxNotifs), anyFloat())) + .thenReturn((float) stackHeightAfterUpdate); + mStackScroller.onChildHeightChanged(row, /* needsAnimation = */ false); + + // Then the stack heights are updated + assertThat(mStackScroller.getIntrinsicStackHeight()).isEqualTo(stackHeightAfterUpdate); + assertThat(mAmbientState.getStackEndHeight()).isEqualTo(stackHeightAfterUpdate); + } + + @Test @DisableSceneContainer public void testSetMaxDisplayedNotifications_notifiesListeners() { ExpandableView.OnHeightChangedListener listener = 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/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 33a4b7ef3ed6..38ddb3e426fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -45,8 +45,6 @@ import static org.mockito.Mockito.when; import android.animation.Animator; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; import android.graphics.Color; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; @@ -154,7 +152,6 @@ public class ScrimControllerTest extends SysuiTestCase { private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository = mKosmos.getKeyguardTransitionRepository(); @Mock private KeyguardInteractor mKeyguardInteractor; - @Mock private TypedArray mMockTypedArray; // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @@ -236,12 +233,8 @@ public class ScrimControllerTest extends SysuiTestCase { public void setup() { MockitoAnnotations.initMocks(this); mContext = spy(getContext()); - when(mContext.obtainStyledAttributes( - new int[]{com.android.internal.R.attr.materialColorSurface})) - .thenReturn(mMockTypedArray); - - when(mMockTypedArray.getColorStateList(anyInt())) - .thenAnswer((invocation) -> ColorStateList.valueOf(mSurfaceColor)); + when(mContext.getColor(com.android.internal.R.color.materialColorSurface)) + .thenAnswer(invocation -> mSurfaceColor); mScrimBehind = spy(new ScrimView(mContext)); mScrimInFront = new ScrimView(mContext); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index 1f68195a9acc..ad92b318b0b9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.domain.interactor +import android.content.testableContext import android.os.userManager import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.communal.data.repository.communalMediaRepository @@ -34,6 +35,7 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.plugins.activityStarter +import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.settings.userTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController @@ -67,6 +69,13 @@ val Kosmos.communalInteractor by Fixture { val Kosmos.editWidgetsActivityStarter by Fixture<EditWidgetsActivityStarter> { mock() } +fun Kosmos.setCommunalV2ConfigEnabled(enabled: Boolean) { + testableContext.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + enabled, + ) +} + suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) { fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled) if (enabled) { @@ -76,6 +85,15 @@ suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) { } } +suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean) { + setCommunalV2ConfigEnabled(true) + if (enabled) { + fakeUserRepository.asMainUser() + } else { + fakeUserRepository.asDefaultUser() + } +} + suspend fun Kosmos.setCommunalAvailable(available: Boolean) { setCommunalEnabled(available) with(fakeKeyguardRepository) { @@ -83,3 +101,12 @@ suspend fun Kosmos.setCommunalAvailable(available: Boolean) { setKeyguardShowing(available) } } + +suspend fun Kosmos.setCommunalV2Available(available: Boolean) { + setCommunalV2ConfigEnabled(true) + setCommunalEnabled(available) + with(fakeKeyguardRepository) { + setIsEncryptedOrLockdown(!available) + setKeyguardShowing(available) + } +} 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/globalactions/GlobalActionsDialogLiteKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/globalactions/GlobalActionsDialogLiteKosmos.kt new file mode 100644 index 000000000000..63bfa52e9720 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/globalactions/GlobalActionsDialogLiteKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.globalactions + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +/** Provides a mock */ +val Kosmos.globalActionsDialogLite: GlobalActionsDialogLite by Kosmos.Fixture { mock() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt index 552cd9488657..4cb8a416124f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt @@ -25,6 +25,7 @@ import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.keyboard.shortcut.data.repository.CustomInputGesturesRepository import com.android.systemui.keyboard.shortcut.data.repository.CustomShortcutCategoriesRepository import com.android.systemui.keyboard.shortcut.data.repository.DefaultShortcutCategoriesRepository +import com.android.systemui.keyboard.shortcut.data.repository.InputGestureDataAdapter import com.android.systemui.keyboard.shortcut.data.repository.InputGestureMaps import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesUtils import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository @@ -112,6 +113,8 @@ val Kosmos.defaultShortcutCategoriesRepository by val Kosmos.inputGestureMaps by Kosmos.Fixture { InputGestureMaps(applicationContext) } +val Kosmos.inputGestureDataAdapter by Kosmos.Fixture { InputGestureDataAdapter(userTracker, inputGestureMaps, applicationContext)} + val Kosmos.customInputGesturesRepository by Kosmos.Fixture { CustomInputGesturesRepository(userTracker, testDispatcher) } @@ -122,8 +125,7 @@ val Kosmos.customShortcutCategoriesRepository by applicationCoroutineScope, testDispatcher, shortcutCategoriesUtils, - applicationContext, - inputGestureMaps, + inputGestureDataAdapter, customInputGesturesRepository, fakeInputManager.inputManager, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt index 10b073e8f331..2e6d8ed5aa5b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/plugins/statusbar/StatusBarStateControllerKosmos.kt @@ -28,6 +28,7 @@ import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.statusbar.FakeStatusBarStateController import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.util.mockito.mock @@ -49,3 +50,6 @@ var Kosmos.statusBarStateController: SysuiStatusBarStateController by { alternateBouncerInteractor }, ) } + +var Kosmos.fakeStatusBarStateController: SysuiStatusBarStateController by + Kosmos.Fixture { FakeStatusBarStateController() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt index c574463eb258..49957f0b43cc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.qs.composefragment.viewmodel import android.content.res.mainResources import androidx.lifecycle.LifecycleCoroutineScope +import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -33,6 +34,7 @@ import com.android.systemui.qs.panels.domain.interactor.tileSquishinessInteracto import com.android.systemui.qs.panels.ui.viewmodel.inFirstPageViewModel import com.android.systemui.qs.panels.ui.viewmodel.mediaInRowInLandscapeViewModelFactory import com.android.systemui.qs.ui.viewmodel.quickSettingsContainerViewModelFactory +import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.shade.transition.largeScreenShadeInterpolator import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor @@ -56,6 +58,7 @@ val Kosmos.qsFragmentComposeViewModelFactory by disableFlagsInteractor, keyguardTransitionInteractor, largeScreenShadeInterpolator, + shadeInteractor, configurationInteractor, largeScreenHeaderHelper, tileSquishinessInteractor, @@ -66,6 +69,7 @@ val Kosmos.qsFragmentComposeViewModelFactory by qqsMediaHost, qsMediaHost, usingMediaInComposeFragment, + uiEventLoggerFake, lifecycleScope, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt index 4acedaa9044d..322b412fb054 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt @@ -18,5 +18,4 @@ package com.android.systemui.qs.panels.data.repository import com.android.systemui.kosmos.Kosmos -var Kosmos.gridLayoutTypeRepository: GridLayoutTypeRepository by - Kosmos.Fixture { GridLayoutTypeRepositoryImpl() } +var Kosmos.gridLayoutTypeRepository by Kosmos.Fixture { GridLayoutTypeRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt index c9516429553b..40c3c96ff241 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt @@ -20,10 +20,19 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository import com.android.systemui.qs.panels.shared.model.GridLayoutType import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType +import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType import com.android.systemui.qs.panels.ui.compose.GridLayout +import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout +import com.android.systemui.qs.panels.ui.compose.paginatedGridLayout +import com.android.systemui.shade.domain.interactor.shadeModeInteractor val Kosmos.gridLayoutTypeInteractor by - Kosmos.Fixture { GridLayoutTypeInteractor(gridLayoutTypeRepository) } + Kosmos.Fixture { GridLayoutTypeInteractor(gridLayoutTypeRepository, shadeModeInteractor) } val Kosmos.gridLayoutMap: Map<GridLayoutType, GridLayout> by - Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridLayout)) } + Kosmos.Fixture { + mapOf( + Pair(InfiniteGridLayoutType, infiniteGridLayout), + Pair(PaginatedGridLayoutType, paginatedGridLayout), + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayoutKosmos.kt new file mode 100644 index 000000000000..f412d98a9d4f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayoutKosmos.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.ui.compose + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout +import com.android.systemui.qs.panels.ui.viewmodel.paginatedGridViewModelFactory + +val Kosmos.paginatedGridLayout by + Kosmos.Fixture { PaginatedGridLayout(paginatedGridViewModelFactory, infiniteGridLayout) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayoutKosmos.kt index 6fe860cfd0d3..f57806c8b678 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayoutKosmos.kt @@ -14,11 +14,10 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.domain.interactor +package com.android.systemui.qs.panels.ui.compose.infinitegrid import com.android.systemui.haptics.msdl.tileHapticsViewModelFactoryProvider import com.android.systemui.kosmos.Kosmos -import com.android.systemui.qs.panels.ui.compose.infinitegrid.InfiniteGridLayout import com.android.systemui.qs.panels.ui.viewmodel.detailsViewModel import com.android.systemui.qs.panels.ui.viewmodel.iconTilesViewModel import com.android.systemui.qs.panels.ui.viewmodel.infiniteGridViewModelFactory diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelKosmos.kt index 33227a4fcc62..71408f6adffd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModelKosmos.kt @@ -17,14 +17,16 @@ package com.android.systemui.qs.panels.ui.viewmodel import android.content.applicationContext +import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.qs.panels.domain.interactor.editTilesListInteractor import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor -import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout import com.android.systemui.qs.panels.domain.interactor.tilesAvailabilityInteractor +import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor import com.android.systemui.qs.pipeline.domain.interactor.minimumTilesInteractor @@ -35,10 +37,12 @@ val Kosmos.editModeViewModel by currentTilesInteractor, tilesAvailabilityInteractor, minimumTilesInteractor, + uiEventLoggerFake, configurationInteractor, applicationContext, infiniteGridLayout, applicationCoroutineScope, + testDispatcher, gridLayoutTypeInteractor, gridLayoutMap, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt index 5c71ba2f8bbd..128cfcad5c45 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModelKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.development.ui.viewmodel.buildNumberViewModelFactory import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.domain.interactor.paginatedGridInteractor +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.editModeButtonViewModelFactory val Kosmos.paginatedGridViewModel by Kosmos.Fixture { @@ -33,3 +34,10 @@ val Kosmos.paginatedGridViewModel by falsingInteractor, ) } + +val Kosmos.paginatedGridViewModelFactory by + Kosmos.Fixture { + object : PaginatedGridViewModel.Factory { + override fun create() = paginatedGridViewModel + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt index 9481fcac97d6..e79d213a8ffb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt @@ -20,7 +20,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor -import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout +import com.android.systemui.qs.panels.ui.compose.infinitegrid.infiniteGridLayout import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor val Kosmos.tileGridViewModel by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelKosmos.kt index b8d3ff425f20..8ae1332c387a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeButtonViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/EditModeButtonViewModelKosmos.kt @@ -14,10 +14,11 @@ * limitations under the License. */ -package com.android.systemui.qs.panels.ui.viewmodel +package com.android.systemui.qs.panels.ui.viewmodel.toolbar import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel val Kosmos.editModeButtonViewModelFactory by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt new file mode 100644 index 000000000000..52d8a3aac836 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.panels.ui.viewmodel.toolbar + +import android.content.applicationContext +import com.android.systemui.classifier.domain.interactor.falsingInteractor +import com.android.systemui.globalactions.globalActionsDialogLite +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.footerActionsInteractor + +val Kosmos.toolbarViewModelFactory by + Kosmos.Fixture { + object : ToolbarViewModel.Factory { + override fun create(): ToolbarViewModel { + return ToolbarViewModel( + editModeButtonViewModelFactory, + footerActionsInteractor, + { globalActionsDialogLite }, + falsingInteractor, + applicationContext, + ) + } + } + } 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/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt index 6afc0d803f8d..aa6ce9a433df 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt @@ -22,6 +22,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.detailsViewModel import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.quickQuickSettingsViewModelFactory import com.android.systemui.qs.panels.ui.viewmodel.tileGridViewModel +import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory val Kosmos.quickSettingsContainerViewModelFactory by Kosmos.Fixture { @@ -36,6 +37,7 @@ val Kosmos.quickSettingsContainerViewModelFactory by tileGridViewModel, editModeViewModel, detailsViewModel, + toolbarViewModelFactory, ) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt index db4df38e038a..f2af619a4ad7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorKosmos.kt @@ -17,25 +17,24 @@ package com.android.systemui.shade.domain.interactor import android.content.mockedContext -import android.view.mockWindowManager +import android.window.WindowContext import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.scene.ui.view.mockShadeRootView import com.android.systemui.shade.ShadeWindowLayoutParams import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository import java.util.Optional +import org.mockito.kotlin.mock -val Kosmos.shadeLayoutParams by Kosmos.Fixture { - ShadeWindowLayoutParams.create(mockedContext) -} +val Kosmos.shadeLayoutParams by Kosmos.Fixture { ShadeWindowLayoutParams.create(mockedContext) } + +val Kosmos.mockedWindowContext by Kosmos.Fixture { mock<WindowContext>() } val Kosmos.shadeDisplaysInteractor by Kosmos.Fixture { ShadeDisplaysInteractor( Optional.of(mockShadeRootView), fakeShadeDisplaysRepository, - mockedContext, - shadeLayoutParams, - mockWindowManager, + mockedWindowContext, testScope.backgroundScope, testScope.backgroundScope.coroutineContext, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerKosmos.kt new file mode 100644 index 000000000000..fa5bd7a90fcf --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerKosmos.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.plugins.statusbar.statusBarStateController +import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.statusbar.policy.keyguardStateController +import org.mockito.kotlin.mock + +var Kosmos.dynamicPrivacyController: DynamicPrivacyController by + Kosmos.Fixture { + DynamicPrivacyController( + notificationLockscreenUserManager, + keyguardStateController, + statusBarStateController, + ) + } + +var Kosmos.mockDynamicPrivacyController: DynamicPrivacyController by Kosmos.Fixture { mock() } 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 new file mode 100644 index 000000000000..88bf9a5f2d5b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.coordinator + +import com.android.keyguard.keyguardUpdateMonitor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.plugins.statusbar.statusBarStateController +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.statusbar.notification.dynamicPrivacyController +import com.android.systemui.statusbar.notificationLockscreenUserManager +import com.android.systemui.statusbar.policy.keyguardStateController +import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionController +import com.android.systemui.user.domain.interactor.selectedUserInteractor +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +var Kosmos.sensitiveContentCoordinator: SensitiveContentCoordinator by + Kosmos.Fixture { + SensitiveContentCoordinatorImpl( + dynamicPrivacyController, + notificationLockscreenUserManager, + keyguardUpdateMonitor, + statusBarStateController, + keyguardStateController, + selectedUserInteractor, + sensitiveNotificationProtectionController, + deviceEntryInteractor, + sceneInteractor, + testScope.backgroundScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt index 3963d7c5be63..766b280334c8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt @@ -23,5 +23,6 @@ import com.android.systemui.statusbar.StatusBarIconView fun inCallModel( startTimeMs: Long, notificationIcon: StatusBarIconView? = null, - intent: PendingIntent? = null -) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent) + intent: PendingIntent? = null, + notificationKey: String = "test", +) = OngoingCallModel.InCall(startTimeMs, notificationIcon, intent, notificationKey) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerKosmos.kt new file mode 100644 index 000000000000..8f9184d1dbf3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerKosmos.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +var Kosmos.sensitiveNotificationProtectionController: SensitiveNotificationProtectionController by + Kosmos.Fixture { mockSensitiveNotificationProtectionController } +val Kosmos.mockSensitiveNotificationProtectionController: + SensitiveNotificationProtectionController by + Kosmos.Fixture { mock<SensitiveNotificationProtectionController>() } 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/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Combinators.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Combinators.kt index 8bf3a43765ae..ae9b8c85910f 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Combinators.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/Combinators.kt @@ -17,6 +17,7 @@ package com.android.systemui.kairos import com.android.systemui.kairos.util.These +import com.android.systemui.kairos.util.WithPrev import com.android.systemui.kairos.util.just import com.android.systemui.kairos.util.none import kotlinx.coroutines.flow.Flow @@ -27,15 +28,18 @@ import kotlinx.coroutines.flow.conflate * Returns a [TFlow] that emits the value sampled from the [Transactional] produced by each emission * of the original [TFlow], within the same transaction of the original emission. */ +@ExperimentalFrpApi fun <A> TFlow<Transactional<A>>.sampleTransactionals(): TFlow<A> = map { it.sample() } /** @see FrpTransactionScope.sample */ +@ExperimentalFrpApi fun <A, B, C> TFlow<A>.sample( state: TState<B>, transform: suspend FrpTransactionScope.(A, B) -> C, ): TFlow<C> = map { transform(it, state.sample()) } /** @see FrpTransactionScope.sample */ +@ExperimentalFrpApi fun <A, B, C> TFlow<A>.sample( transactional: Transactional<B>, transform: suspend FrpTransactionScope.(A, B) -> C, @@ -50,6 +54,7 @@ fun <A, B, C> TFlow<A>.sample( * * @see sample */ +@ExperimentalFrpApi fun <A, B, C> TFlow<A>.samplePromptly( state: TState<B>, transform: suspend FrpTransactionScope.(A, B) -> C, @@ -70,19 +75,10 @@ fun <A, B, C> TFlow<A>.samplePromptly( } /** - * Returns a [TState] containing a map with a snapshot of the current state of each [TState] in the - * original map. - */ -fun <K, A> Map<K, TState<A>>.combineValues(): TState<Map<K, A>> = - asIterable() - .map { (k, state) -> state.map { v -> k to v } } - .combine() - .map { entries -> entries.toMap() } - -/** * Returns a cold [Flow] that, when collected, emits from this [TFlow]. [network] is needed to * transactionally connect to / disconnect from the [TFlow] when collection starts/stops. */ +@ExperimentalFrpApi fun <A> TFlow<A>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { observe { trySend(it) } } }.conflate() @@ -90,6 +86,7 @@ fun <A> TFlow<A>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = * Returns a cold [Flow] that, when collected, emits from this [TState]. [network] is needed to * transactionally connect to / disconnect from the [TState] when collection starts/stops. */ +@ExperimentalFrpApi fun <A> TState<A>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { observe { trySend(it) } } }.conflate() @@ -99,6 +96,7 @@ fun <A> TState<A>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = * * When collection is cancelled, so is the [FrpSpec]. This means all ongoing work is cleaned up. */ +@ExperimentalFrpApi @JvmName("flowSpecToColdConflatedFlow") fun <A> FrpSpec<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { applySpec().observe { trySend(it) } } }.conflate() @@ -109,6 +107,7 @@ fun <A> FrpSpec<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = * * When collection is cancelled, so is the [FrpSpec]. This means all ongoing work is cleaned up. */ +@ExperimentalFrpApi @JvmName("stateSpecToColdConflatedFlow") fun <A> FrpSpec<TState<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { applySpec().observe { trySend(it) } } }.conflate() @@ -117,6 +116,7 @@ fun <A> FrpSpec<TState<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = * Returns a cold [Flow] that, when collected, applies this [Transactional] in a new transaction in * this [network], and then emits from the returned [TFlow]. */ +@ExperimentalFrpApi @JvmName("transactionalFlowToColdConflatedFlow") fun <A> Transactional<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { sample().observe { trySend(it) } } }.conflate() @@ -125,6 +125,7 @@ fun <A> Transactional<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A * Returns a cold [Flow] that, when collected, applies this [Transactional] in a new transaction in * this [network], and then emits from the returned [TState]. */ +@ExperimentalFrpApi @JvmName("transactionalStateToColdConflatedFlow") fun <A> Transactional<TState<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { sample().observe { trySend(it) } } }.conflate() @@ -135,6 +136,7 @@ fun <A> Transactional<TState<A>>.toColdConflatedFlow(network: FrpNetwork): Flow< * * When collection is cancelled, so is the [FrpStateful]. This means all ongoing work is cleaned up. */ +@ExperimentalFrpApi @JvmName("statefulFlowToColdConflatedFlow") fun <A> FrpStateful<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { applyStateful().observe { trySend(it) } } }.conflate() @@ -145,11 +147,13 @@ fun <A> FrpStateful<TFlow<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> * * When collection is cancelled, so is the [FrpStateful]. This means all ongoing work is cleaned up. */ +@ExperimentalFrpApi @JvmName("statefulStateToColdConflatedFlow") fun <A> FrpStateful<TState<A>>.toColdConflatedFlow(network: FrpNetwork): Flow<A> = channelFlow { network.activateSpec { applyStateful().observe { trySend(it) } } }.conflate() /** Return a [TFlow] that emits from the original [TFlow] only when [state] is `true`. */ +@ExperimentalFrpApi fun <A> TFlow<A>.filter(state: TState<Boolean>): TFlow<A> = filter { state.sample() } private fun Iterable<Boolean>.allTrue() = all { it } @@ -157,13 +161,15 @@ private fun Iterable<Boolean>.allTrue() = all { it } private fun Iterable<Boolean>.anyTrue() = any { it } /** Returns a [TState] that is `true` only when all of [states] are `true`. */ +@ExperimentalFrpApi fun allOf(vararg states: TState<Boolean>): TState<Boolean> = combine(*states) { it.allTrue() } /** Returns a [TState] that is `true` when any of [states] are `true`. */ +@ExperimentalFrpApi fun anyOf(vararg states: TState<Boolean>): TState<Boolean> = combine(*states) { it.anyTrue() } /** Returns a [TState] containing the inverse of the Boolean held by the original [TState]. */ -fun not(state: TState<Boolean>): TState<Boolean> = state.mapCheapUnsafe { !it } +@ExperimentalFrpApi fun not(state: TState<Boolean>): TState<Boolean> = state.mapCheapUnsafe { !it } /** * Represents a modal FRP sub-network. @@ -177,6 +183,7 @@ fun not(state: TState<Boolean>): TState<Boolean> = state.mapCheapUnsafe { !it } * * @see FrpStatefulMode */ +@ExperimentalFrpApi fun interface FrpBuildMode<out A> { /** * Invoked when this mode is enabled. Returns a value and a [TFlow] that signals a switch to a @@ -192,6 +199,7 @@ fun interface FrpBuildMode<out A> { * * @see FrpBuildMode */ +@ExperimentalFrpApi val <A> FrpBuildMode<A>.compiledFrpSpec: FrpSpec<TState<A>> get() = frpSpec { var modeChangeEvents by TFlowLoop<FrpBuildMode<A>>() @@ -215,6 +223,7 @@ val <A> FrpBuildMode<A>.compiledFrpSpec: FrpSpec<TState<A>> * * @see FrpBuildMode */ +@ExperimentalFrpApi fun interface FrpStatefulMode<out A> { /** * Invoked when this mode is enabled. Returns a value and a [TFlow] that signals a switch to a @@ -230,6 +239,7 @@ fun interface FrpStatefulMode<out A> { * * @see FrpBuildMode */ +@ExperimentalFrpApi val <A> FrpStatefulMode<A>.compiledStateful: FrpStateful<TState<A>> get() = statefully { var modeChangeEvents by TFlowLoop<FrpStatefulMode<A>>() @@ -246,5 +256,18 @@ val <A> FrpStatefulMode<A>.compiledStateful: FrpStateful<TState<A>> * Runs [spec] in this [FrpBuildScope], and then re-runs it whenever [rebuildSignal] emits. Returns * a [TState] that holds the result of the currently-active [FrpSpec]. */ +@ExperimentalFrpApi fun <A> FrpBuildScope.rebuildOn(rebuildSignal: TFlow<*>, spec: FrpSpec<A>): TState<A> = rebuildSignal.map { spec }.holdLatestSpec(spec) + +/** + * Like [stateChanges] but also includes the old value of this [TState]. + * + * Shorthand for: + * ``` kotlin + * stateChanges.map { WithPrev(previousValue = sample(), newValue = it) } + * ``` + */ +@ExperimentalFrpApi +val <A> TState<A>.transitions: TFlow<WithPrev<A, A>> + get() = stateChanges.map { WithPrev(previousValue = sample(), newValue = it) } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpBuildScope.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpBuildScope.kt index 4de6deb3dc53..209a402bd629 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpBuildScope.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpBuildScope.kt @@ -38,6 +38,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.dropWhile +import kotlinx.coroutines.flow.scan import kotlinx.coroutines.launch /** A function that modifies the FrpNetwork. */ @@ -596,6 +597,26 @@ interface FrpBuildScope : FrpStateScope { fun <A> Flow<A>.toTState(initialValue: A): TState<A> = toTFlow().hold(initialValue) /** + * Shorthand for: + * ```kotlin + * flow.scan(initialValue, operation).toTFlow().hold(initialValue) + * ``` + */ + @ExperimentalFrpApi + fun <A, B> Flow<A>.scanToTState(initialValue: B, operation: (B, A) -> B): TState<B> = + scan(initialValue, operation).toTFlow().hold(initialValue) + + /** + * Shorthand for: + * ```kotlin + * flow.scan(initialValue) { a, f -> f(a) }.toTFlow().hold(initialValue) + * ``` + */ + @ExperimentalFrpApi + fun <A> Flow<(A) -> A>.scanToTState(initialValue: A): TState<A> = + scanToTState(initialValue) { a, f -> f(a) } + + /** * Invokes [block] whenever this [TFlow] emits a value. [block] receives an [FrpBuildScope] that * can be used to make further modifications to the FRP network, and/or perform side-effects via * [effect]. diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpEffectScope.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpEffectScope.kt index be2eb4312476..b39dcc131b1d 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpEffectScope.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpEffectScope.kt @@ -22,16 +22,17 @@ import kotlinx.coroutines.CoroutineScope /** * Scope for external side-effects triggered by the Frp network. This still occurs within the * context of a transaction, so general suspending calls are disallowed to prevent blocking the - * transaction. You can use [frpCoroutineScope] to [launch] new coroutines to perform long-running - * asynchronous work. This scope is alive for the duration of the containing [FrpBuildScope] that - * this side-effect scope is running in. + * transaction. You can use [frpCoroutineScope] to [launch][kotlinx.coroutines.launch] new + * coroutines to perform long-running asynchronous work. This scope is alive for the duration of the + * containing [FrpBuildScope] that this side-effect scope is running in. */ @RestrictsSuspension @ExperimentalFrpApi interface FrpEffectScope : FrpTransactionScope { /** * A [CoroutineScope] whose lifecycle lives for as long as this [FrpEffectScope] is alive. This - * is generally until the [Job] returned by [FrpBuildScope.effect] is cancelled. + * is generally until the [Job][kotlinx.coroutines.Job] returned by [FrpBuildScope.effect] is + * cancelled. */ @ExperimentalFrpApi val frpCoroutineScope: CoroutineScope diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpNetwork.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpNetwork.kt index b688eafe12e9..97252b4a199a 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpNetwork.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/FrpNetwork.kt @@ -137,7 +137,7 @@ internal class LocalFrpNetwork( override suspend fun <R> transact(block: suspend FrpTransactionScope.() -> R): R { val result = CompletableDeferred<R>(coroutineContext[Job]) @Suppress("DeferredResultUnused") - network.transaction { + network.transaction("FrpNetwork.transact") { val buildScope = BuildScopeImpl( stateScope = StateScopeImpl(evalScope = this, endSignal = endSignal), @@ -151,7 +151,7 @@ internal class LocalFrpNetwork( override suspend fun activateSpec(spec: FrpSpec<*>) { val job = network - .transaction { + .transaction("FrpNetwork.activateSpec") { val buildScope = BuildScopeImpl( stateScope = StateScopeImpl(evalScope = this, endSignal = endSignal), @@ -166,7 +166,8 @@ internal class LocalFrpNetwork( override fun <In, Out> coalescingMutableTFlow( coalesce: (old: Out, new: In) -> Out, getInitialValue: () -> Out, - ): CoalescingMutableTFlow<In, Out> = CoalescingMutableTFlow(coalesce, network, getInitialValue) + ): CoalescingMutableTFlow<In, Out> = + CoalescingMutableTFlow(null, coalesce, network, getInitialValue) override fun <T> mutableTFlow(): MutableTFlow<T> = MutableTFlow(network) diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TFlow.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TFlow.kt index 7ba1aca31eae..a175e2e20e46 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TFlow.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TFlow.kt @@ -467,12 +467,12 @@ fun <A> TState<TFlow<A>>.switchPromptly(): TFlow<A> { @ExperimentalFrpApi class CoalescingMutableTFlow<In, Out> internal constructor( + internal val name: String?, internal val coalesce: (old: Out, new: In) -> Out, internal val network: Network, private val getInitialValue: () -> Out, internal val impl: InputNode<Out> = InputNode(), ) : TFlow<Out>() { - internal val name: String? = null internal val storage = AtomicReference(false to getInitialValue()) override fun toString(): String = "${this::class.simpleName}@$hashString" @@ -490,7 +490,7 @@ internal constructor( val (scheduled, _) = storage.getAndUpdate { (_, old) -> true to coalesce(old, value) } if (!scheduled) { @Suppress("DeferredResultUnused") - network.transaction { + network.transaction("CoalescingMutableTFlow${name?.let { "($name)" }.orEmpty()}.emit") { impl.visit(this, storage.getAndSet(false to getInitialValue()).second) } } @@ -520,16 +520,16 @@ internal constructor(internal val network: Network, internal val impl: InputNode @ExperimentalFrpApi suspend fun emit(value: T) { coroutineScope { + var jobOrNull: Job? = null val newEmit = async(start = CoroutineStart.LAZY) { - network.transaction { impl.visit(this, value) }.await() + jobOrNull?.join() + network + .transaction("MutableTFlow($name).emit") { impl.visit(this, value) } + .await() } - val jobOrNull = storage.getAndSet(newEmit) - if (jobOrNull?.isActive != true) { - newEmit.await() - } else { - jobOrNull.join() - } + jobOrNull = storage.getAndSet(newEmit) + newEmit.await() } } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TState.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TState.kt index a4c695657f8d..80e74748a375 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TState.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/TState.kt @@ -121,7 +121,7 @@ fun <A, B, C> TState<A>.combineWith( /** * Splits a [TState] of pairs into a pair of [TFlows][TState], where each returned [TState] holds - * hald of the original. + * half of the original. * * Shorthand for: * ```kotlin @@ -312,6 +312,57 @@ fun <A, B, C, D, Z> combine( ) } +/** + * Returns a [TState] whose value is generated with [transform] by combining the current values of + * each given [TState]. + * + * @see TState.combineWith + */ +@ExperimentalFrpApi +fun <A, B, C, D, E, Z> combine( + stateA: TState<A>, + stateB: TState<B>, + stateC: TState<C>, + stateD: TState<D>, + stateE: TState<E>, + transform: suspend FrpScope.(A, B, C, D, E) -> Z, +): TState<Z> { + val operatorName = "combine" + val name = operatorName + return TStateInit( + init(name) { + coroutineScope { + val dl1: Deferred<TStateImpl<A>> = async { + stateA.init.connect(evalScope = this@init) + } + val dl2: Deferred<TStateImpl<B>> = async { + stateB.init.connect(evalScope = this@init) + } + val dl3: Deferred<TStateImpl<C>> = async { + stateC.init.connect(evalScope = this@init) + } + val dl4: Deferred<TStateImpl<D>> = async { + stateD.init.connect(evalScope = this@init) + } + val dl5: Deferred<TStateImpl<E>> = async { + stateE.init.connect(evalScope = this@init) + } + zipStates( + name, + operatorName, + dl1.await(), + dl2.await(), + dl3.await(), + dl4.await(), + dl5.await(), + ) { a, b, c, d, e -> + NoScope.runInFrpScope { transform(a, b, c, d, e) } + } + } + } + ) +} + /** Returns a [TState] by applying [transform] to the value held by the original [TState]. */ @ExperimentalFrpApi fun <A, B> TState<A>.flatMap(transform: suspend FrpScope.(A) -> TState<B>): TState<B> { @@ -367,7 +418,7 @@ fun <A> TState<A>.selector(numDistinctValues: Int? = null): TStateSelector<A> = * @see selector */ @ExperimentalFrpApi -class TStateSelector<A> +class TStateSelector<in A> internal constructor( private val upstream: TState<A>, private val groupedChanges: GroupedTFlow<A, Boolean>, @@ -406,6 +457,7 @@ internal constructor(internal val network: Network, initialValue: Deferred<T>) : private val input: CoalescingMutableTFlow<Deferred<T>, Deferred<T>?> = CoalescingMutableTFlow( + name = null, coalesce = { _, new -> new }, network = network, getInitialValue = { null }, @@ -423,7 +475,7 @@ internal constructor(internal val network: Network, initialValue: Deferred<T>) : .cached() state = TStateSource(name, operatorName, initialValue, calm) @Suppress("DeferredResultUnused") - network.transaction { + network.transaction("MutableTState.init") { calm.activate(evalScope = this, downstream = Schedulable.S(state))?.let { (connection, needsEval) -> state.upstreamConnection = connection diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/debug/Debug.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/debug/Debug.kt index 4f302a14ff00..0674a2e75659 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/debug/Debug.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/debug/Debug.kt @@ -31,6 +31,8 @@ import com.android.systemui.kairos.internal.TStateSource import com.android.systemui.kairos.util.Just import com.android.systemui.kairos.util.Maybe import com.android.systemui.kairos.util.None +import com.android.systemui.kairos.util.flatMap +import com.android.systemui.kairos.util.map import com.android.systemui.kairos.util.none import com.android.systemui.kairos.util.orElseGet @@ -178,3 +180,24 @@ private fun <A> TStateImpl<A>.getUnsafe(): Maybe<A> = is TStateSource -> getStorageUnsafe() is DerivedMapCheap<*, *> -> none } + +private fun <A> TStateImpl<A>.getUnsafeWithEpoch(): Maybe<Pair<A, Long>> = + when (this) { + is TStateDerived -> getCachedUnsafe().map { it to invalidatedEpoch } + is TStateSource -> getStorageUnsafe().map { it to writeEpoch } + is DerivedMapCheap<*, *> -> none + } + +/** + * Returns the current value held in this [TState], or [none] if the [TState] has not been + * initialized. + * + * The returned [Long] is the *epoch* at which the internal cache was last updated. This can be used + * to identify values which are out-of-date. + */ +fun <A> TState<A>.sampleUnsafe(): Maybe<Pair<A, Long>> = + when (this) { + is MutableTState -> tState.init.getUnsafe().flatMap { it.getUnsafeWithEpoch() } + is TStateInit -> init.getUnsafe().flatMap { it.getUnsafeWithEpoch() } + is TStateLoop -> this.init.getUnsafe().flatMap { it.getUnsafeWithEpoch() } + } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/BuildScopeImpl.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/BuildScopeImpl.kt index 90f1aea3e42f..7e6384925f38 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/BuildScopeImpl.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/BuildScopeImpl.kt @@ -34,9 +34,9 @@ import com.android.systemui.kairos.TFlowInit import com.android.systemui.kairos.groupByKey import com.android.systemui.kairos.init import com.android.systemui.kairos.internal.util.childScope -import com.android.systemui.kairos.internal.util.launchOnCancel import com.android.systemui.kairos.internal.util.mapValuesParallel import com.android.systemui.kairos.launchEffect +import com.android.systemui.kairos.mergeLeft import com.android.systemui.kairos.util.Just import com.android.systemui.kairos.util.Maybe import com.android.systemui.kairos.util.None @@ -49,7 +49,6 @@ import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.startCoroutine import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableJob -import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.Job @@ -86,8 +85,7 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope builder: suspend S.() -> Unit, ): TFlow<A> { var job: Job? = null - val stopEmitter = newStopEmitter() - val handle = this.job.invokeOnCompletion { stopEmitter.emit(Unit) } + val stopEmitter = newStopEmitter("buildTFlow") // Create a child scope that will be kept alive beyond the end of this transaction. val childScope = coroutineScope.childScope() lateinit var emitter: Pair<T, S> @@ -99,7 +97,6 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope reenterBuildScope(this@BuildScopeImpl, childScope).runInBuildScope { launchEffect { builder(emitter.second) - handle.dispose() stopEmitter.emit(Unit) } } @@ -110,7 +107,7 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope }, ) emitter = constructFlow(inputNode) - return with(frpScope) { emitter.first.takeUntil(stopEmitter) } + return with(frpScope) { emitter.first.takeUntil(mergeLeft(stopEmitter, endSignal)) } } private fun <T> tFlowInternal(builder: suspend FrpProducerScope<T>.() -> Unit): TFlow<T> = @@ -134,7 +131,8 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope ): TFlow<Out> = buildTFlow( constructFlow = { inputNode -> - val flow = CoalescingMutableTFlow(coalesce, network, getInitialValue, inputNode) + val flow = + CoalescingMutableTFlow(null, coalesce, network, getInitialValue, inputNode) flow to object : FrpCoalescingProducerScope<In> { override fun emit(value: In) { @@ -164,11 +162,13 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope val subRef = AtomicReference<Maybe<Output<A>>>(null) val childScope = coroutineScope.childScope() // When our scope is cancelled, deactivate this observer. - childScope.launchOnCancel(CoroutineName("TFlow.observeEffect")) { + childScope.coroutineContext.job.invokeOnCompletion { subRef.getAndSet(None)?.let { output -> if (output is Just) { @Suppress("DeferredResultUnused") - network.transaction { scheduleDeactivation(output.value) } + network.transaction("observeEffect cancelled") { + scheduleDeactivation(output.value) + } } } } @@ -215,7 +215,7 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope } else if (needsEval) { outputNode.schedule(evalScope = stateScope.evalScope) } - } ?: childScope.cancel() + } ?: run { childScope.cancel() } } return childScope.coroutineContext.job } @@ -229,10 +229,7 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope "mapBuild", mapImpl({ init.connect(evalScope = this) }) { spec -> reenterBuildScope(outerScope = this@BuildScopeImpl, childScope) - .runInBuildScope { - val (result, _) = asyncScope { transform(spec) } - result.get() - } + .runInBuildScope { transform(spec) } } .cached(), ) @@ -272,8 +269,9 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope return changes to FrpDeferredValue(initOut) } - private fun newStopEmitter(): CoalescingMutableTFlow<Unit, Unit> = + private fun newStopEmitter(name: String): CoalescingMutableTFlow<Unit, Unit> = CoalescingMutableTFlow( + name = name, coalesce = { _, _: Unit -> }, network = network, getInitialValue = {}, @@ -299,17 +297,19 @@ internal class BuildScopeImpl(val stateScope: StateScopeImpl, val coroutineScope } private fun mutableChildBuildScope(): BuildScopeImpl { - val stopEmitter = newStopEmitter() + val stopEmitter = newStopEmitter("mutableChildBuildScope") val childScope = coroutineScope.childScope() childScope.coroutineContext.job.invokeOnCompletion { stopEmitter.emit(Unit) } // Ensure that once this transaction is done, the new child scope enters the completing // state (kept alive so long as there are child jobs). - scheduleOutput( - OneShot { - // TODO: don't like this cast - (childScope.coroutineContext.job as CompletableJob).complete() - } - ) + // TODO: need to keep the scope alive if it's used to accumulate state. + // Otherwise, stopEmitter will emit early, due to the call to complete(). + // scheduleOutput( + // OneShot { + // // TODO: don't like this cast + // (childScope.coroutineContext.job as CompletableJob).complete() + // } + // ) return BuildScopeImpl( stateScope = StateScopeImpl(evalScope = stateScope.evalScope, endSignal = stopEmitter), coroutineScope = childScope, diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Graph.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Graph.kt index 3aec319881d0..04ce5b6d8785 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Graph.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Graph.kt @@ -86,7 +86,7 @@ internal class DepthTracker { @Volatile private var dirty_depthIsDirect = true @Volatile private var dirty_isIndirectRoot = false - suspend fun schedule(scheduler: Scheduler, node: MuxNode<*, *, *>) { + fun schedule(scheduler: Scheduler, node: MuxNode<*, *, *>) { if (dirty_depthIsDirect) { scheduler.schedule(dirty_directDepth, node) } else { diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/InternalScopes.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/InternalScopes.kt index af864e6c3496..69994ba6e866 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/InternalScopes.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/InternalScopes.kt @@ -66,8 +66,6 @@ internal interface NetworkScope : InitScope { fun schedule(state: TStateSource<*>) - suspend fun schedule(node: MuxNode<*, *, *>) - fun scheduleDeactivation(node: PushNode<*>) fun scheduleDeactivation(output: Output<*>) diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Mux.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Mux.kt index f7ff15f0507b..af68a1e3d83c 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Mux.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Mux.kt @@ -188,6 +188,14 @@ internal sealed class MuxNode<K : Any, V, Output>(val lifecycle: MuxLifecycle<Ou } abstract fun hasCurrentValueLocked(transactionStore: TransactionStore): Boolean + + fun schedule(evalScope: EvalScope) { + // TODO: Potential optimization + // Detect if this node is guaranteed to have a single upstream within this transaction, + // then bypass scheduling it. Instead immediately schedule its downstream and treat this + // MuxNode as a Pull (effectively making it a mapCheap). + depthTracker.schedule(evalScope.scheduler, this) + } } /** An input branch of a mux node, associated with a key. */ @@ -202,7 +210,7 @@ internal class MuxBranchNode<K : Any, V>(private val muxNode: MuxNode<K, V, *>, val upstreamResult = upstream.getPushEvent(evalScope) if (upstreamResult is Just) { muxNode.upstreamData[key] = upstreamResult.value - evalScope.schedule(muxNode) + muxNode.schedule(evalScope) } } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxDeferred.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxDeferred.kt index 08bee855831a..3b9502a5d812 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxDeferred.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxDeferred.kt @@ -409,7 +409,7 @@ internal fun <K : Any, A> switchDeferredImpl( // Schedule for evaluation if any switched-in nodes have already emitted within // this transaction. if (muxNode.upstreamData.isNotEmpty()) { - evalScope.schedule(muxNode) + muxNode.schedule(evalScope) } return muxNode.takeUnless { muxNode.switchedIn.isEmpty() && !isIndirect } } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxPrompt.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxPrompt.kt index cdfafa943121..b291c879b449 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxPrompt.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/MuxPrompt.kt @@ -75,7 +75,7 @@ internal class MuxPromptMovingNode<K : Any, V>( if (depthTracker.dirty_depthIncreased()) { depthTracker.schedule(evalScope.compactor, node = this) } - evalScope.schedule(this) + schedule(evalScope) } else { val compactDownstream = depthTracker.isDirty() if (evalResult != null || compactDownstream) { @@ -291,7 +291,7 @@ internal class MuxPromptPatchNode<K : Any, V>(private val muxNode: MuxPromptMovi val upstreamResult = upstream.getPushEvent(evalScope) if (upstreamResult is Just) { muxNode.patchData = upstreamResult.value - evalScope.schedule(muxNode) + muxNode.schedule(evalScope) } } @@ -451,7 +451,7 @@ internal fun <K : Any, A> switchPromptImpl( // Schedule for evaluation if any switched-in nodes or the patches node have // already emitted within this transaction. if (movingNode.patchData != null || movingNode.upstreamData.isNotEmpty()) { - evalScope.schedule(movingNode) + movingNode.schedule(evalScope) } return movingNode.takeUnless { it.patches == null && it.switchedIn.isEmpty() } diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt index f0df89d780c9..599b18695034 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt @@ -81,11 +81,6 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { stateWrites.add(state) } - // TODO: weird that we have this *and* scheduler exposed - override suspend fun schedule(node: MuxNode<*, *, *>) { - scheduler.schedule(node.depthTracker.dirty_directDepth, node) - } - override fun scheduleDeactivation(node: PushNode<*>) { deactivations.add(node) } @@ -95,9 +90,7 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { } /** Listens for external events and starts FRP transactions. Runs forever. */ - suspend fun runInputScheduler() = coroutineScope { - launch { scheduler.activate() } - launch { compactor.activate() } + suspend fun runInputScheduler() { val actions = mutableListOf<ScheduledAction<*>>() for (first in inputScheduleChan) { // Drain and conflate all transaction requests into a single transaction @@ -125,12 +118,12 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { } /** Evaluates [block] inside of a new transaction when the network is ready. */ - fun <R> transaction(block: suspend EvalScope.() -> R): Deferred<R> = + fun <R> transaction(reason: String, block: suspend EvalScope.() -> R): Deferred<R> = CompletableDeferred<R>(parent = coroutineScope.coroutineContext.job).also { onResult -> val job = coroutineScope.launch { inputScheduleChan.send( - ScheduledAction(onStartTransaction = block, onResult = onResult) + ScheduledAction(reason, onStartTransaction = block, onResult = onResult) ) } onResult.invokeOnCompletion { job.cancel() } @@ -229,6 +222,7 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { } internal class ScheduledAction<T>( + val reason: String, private val onResult: CompletableDeferred<T>? = null, private val onStartTransaction: suspend EvalScope.() -> T, ) { diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Scheduler.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Scheduler.kt index 872fb7a6cb74..c12ef6ae6a5d 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Scheduler.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Scheduler.kt @@ -21,44 +21,34 @@ package com.android.systemui.kairos.internal import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.PriorityBlockingQueue import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch internal interface Scheduler { - suspend fun schedule(depth: Int, node: MuxNode<*, *, *>) + fun schedule(depth: Int, node: MuxNode<*, *, *>) - suspend fun scheduleIndirect(indirectDepth: Int, node: MuxNode<*, *, *>) + fun scheduleIndirect(indirectDepth: Int, node: MuxNode<*, *, *>) } internal class SchedulerImpl : Scheduler { val enqueued = ConcurrentHashMap<MuxNode<*, *, *>, Any>() val scheduledQ = PriorityBlockingQueue<Pair<Int, MuxNode<*, *, *>>>(16, compareBy { it.first }) - val chan = Channel<Pair<Int, MuxNode<*, *, *>>>(Channel.UNLIMITED) - override suspend fun schedule(depth: Int, node: MuxNode<*, *, *>) { + override fun schedule(depth: Int, node: MuxNode<*, *, *>) { if (enqueued.putIfAbsent(node, node) == null) { - chan.send(Pair(depth, node)) + scheduledQ.add(Pair(depth, node)) } } - override suspend fun scheduleIndirect(indirectDepth: Int, node: MuxNode<*, *, *>) { + override fun scheduleIndirect(indirectDepth: Int, node: MuxNode<*, *, *>) { schedule(Int.MIN_VALUE + indirectDepth, node) } - suspend fun activate() { - for (nodeSchedule in chan) { - scheduledQ.add(nodeSchedule) - drainChan() - } - } - internal suspend fun drainEval(network: Network) { drain { runStep -> runStep { muxNode -> network.evalScope { muxNode.visit(this) } } // If any visited MuxPromptNodes had their depths increased, eagerly propagate those - // depth - // changes now before performing further network evaluation. + // depth changes now before performing further network evaluation. network.compactor.drainCompact() } } @@ -71,19 +61,12 @@ internal class SchedulerImpl : Scheduler { crossinline onStep: suspend (runStep: suspend (visit: suspend (MuxNode<*, *, *>) -> Unit) -> Unit) -> Unit ): Unit = coroutineScope { - while (!chan.isEmpty || scheduledQ.isNotEmpty()) { - drainChan() + while (scheduledQ.isNotEmpty()) { val maxDepth = scheduledQ.peek()?.first ?: error("Unexpected empty scheduler") onStep { visit -> runStep(maxDepth, visit) } } } - private suspend fun drainChan() { - while (!chan.isEmpty) { - scheduledQ.add(chan.receive()) - } - } - private suspend inline fun runStep( maxDepth: Int, crossinline visit: suspend (MuxNode<*, *, *>) -> Unit, diff --git a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/TStateImpl.kt b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/TStateImpl.kt index 5cec05c8ef2d..c68b4c366776 100644 --- a/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/TStateImpl.kt +++ b/packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/TStateImpl.kt @@ -314,6 +314,28 @@ internal fun <A, B, C, D, Z> zipStates( @Suppress("UNCHECKED_CAST") transform(a as A, b as B, c as C, d as D) } +internal fun <A, B, C, D, E, Z> zipStates( + name: String?, + operatorName: String, + l1: TStateImpl<A>, + l2: TStateImpl<B>, + l3: TStateImpl<C>, + l4: TStateImpl<D>, + l5: TStateImpl<E>, + transform: suspend EvalScope.(A, B, C, D, E) -> Z, +): TStateImpl<Z> = + zipStates(null, operatorName, mapOf(0 to l1, 1 to l2, 2 to l3, 3 to l4, 4 to l5)).map( + name, + operatorName, + ) { + val a = it.getValue(0) + val b = it.getValue(1) + val c = it.getValue(2) + val d = it.getValue(3) + val e = it.getValue(4) + @Suppress("UNCHECKED_CAST") transform(a as A, b as B, c as C, d as D, e as E) + } + internal fun <K : Any, A> zipStates( name: String?, operatorName: String, diff --git a/packages/SystemUI/utils/kairos/test/com/android/systemui/kairos/KairosTests.kt b/packages/SystemUI/utils/kairos/test/com/android/systemui/kairos/KairosTests.kt index 165230b2aeaf..688adae8fcae 100644 --- a/packages/SystemUI/utils/kairos/test/com/android/systemui/kairos/KairosTests.kt +++ b/packages/SystemUI/utils/kairos/test/com/android/systemui/kairos/KairosTests.kt @@ -1170,12 +1170,12 @@ class KairosTests { mergeIncrementally .onEach { println("patch: $it") } .foldMapIncrementally() - .flatMap { it.combineValues() } + .flatMap { it.combine() } } } } .foldMapIncrementally() - .flatMap { it.combineValues() } + .flatMap { it.combine() } accState.toStateFlow() } @@ -1300,6 +1300,26 @@ class KairosTests { } @Test + fun buildScope_stateAccumulation() = runFrpTest { network -> + val input = network.mutableTFlow<Unit>() + var observedCount: Int? = null + activateSpec(network) { + val (c, j) = asyncScope { input.fold(0) { _, x -> x + 1 } } + deferredBuildScopeAction { c.get().observe { observedCount = it } } + } + runCurrent() + assertEquals(0, observedCount) + + input.emit(Unit) + runCurrent() + assertEquals(1, observedCount) + + input.emit(Unit) + runCurrent() + assertEquals(2, observedCount) + } + + @Test fun effect() = runFrpTest { network -> val input = network.mutableTFlow<Unit>() var effectRunning = false diff --git a/services/appfunctions/Android.bp b/services/appfunctions/Android.bp index eb6e46861898..7337aa26c145 100644 --- a/services/appfunctions/Android.bp +++ b/services/appfunctions/Android.bp @@ -19,6 +19,7 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [ ":services.appfunctions-sources", + ":statslog-appfunctions-java-gen", "java/**/*.logtags", ], libs: ["services.core"], @@ -26,3 +27,10 @@ java_library_static { baseline_filename: "lint-baseline.xml", }, } + +genrule { + name: "statslog-appfunctions-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module appfunctions --javaPackage com.android.server.appfunctions --javaClass AppFunctionsStatsLog --minApiLevel 35", + out: ["java/com/android/server/appfunctions/AppFunctionsStatsLog.java"], +} diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java index 81e83b563945..eaea4435099c 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java @@ -16,6 +16,8 @@ package com.android.server.appfunctions; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -35,6 +37,11 @@ public final class AppFunctionExecutors { /* workQueue= */ new LinkedBlockingQueue<>(), new NamedThreadFactory("AppFunctionExecutors")); + /** Executor for stats logging. */ + public static final ExecutorService LOGGING_THREAD_EXECUTOR = + Executors.newSingleThreadExecutor( + new NamedThreadFactory("AppFunctionsLoggingExecutors")); + static { THREAD_POOL_EXECUTOR.allowCoreThreadTimeOut(true); } diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index c17c34061d1b..9cc5a8c97258 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -30,6 +30,7 @@ import android.app.appfunctions.AppFunctionManagerHelper; import android.app.appfunctions.AppFunctionRuntimeMetadata; import android.app.appfunctions.AppFunctionStaticMetadataHelper; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; +import android.app.appfunctions.ExecuteAppFunctionResponse; import android.app.appfunctions.IAppFunctionEnabledCallback; import android.app.appfunctions.IAppFunctionManager; import android.app.appfunctions.IAppFunctionService; @@ -85,6 +86,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private final ServiceConfig mServiceConfig; private final Context mContext; private final Map<String, Object> mLocks = new WeakHashMap<>(); + private final AppFunctionsLoggerWrapper mLoggerWrapper; public AppFunctionManagerServiceImpl(@NonNull Context context) { this( @@ -93,7 +95,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { context, IAppFunctionService.Stub::asInterface, THREAD_POOL_EXECUTOR), new CallerValidatorImpl(context), new ServiceHelperImpl(context), - new ServiceConfigImpl()); + new ServiceConfigImpl(), + new AppFunctionsLoggerWrapper(context)); } @VisibleForTesting @@ -102,12 +105,14 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { RemoteServiceCaller<IAppFunctionService> remoteServiceCaller, CallerValidator callerValidator, ServiceHelper appFunctionInternalServiceHelper, - ServiceConfig serviceConfig) { + ServiceConfig serviceConfig, + AppFunctionsLoggerWrapper loggerWrapper) { mContext = Objects.requireNonNull(context); mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller); mCallerValidator = Objects.requireNonNull(callerValidator); mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper); mServiceConfig = serviceConfig; + mLoggerWrapper = loggerWrapper; } /** Called when the user is unlocked. */ @@ -146,8 +151,25 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { Objects.requireNonNull(requestInternal); Objects.requireNonNull(executeAppFunctionCallback); + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback = - new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback); + new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback, + new SafeOneTimeExecuteAppFunctionCallback.CompletionCallback() { + @Override + public void finalizeOnSuccess( + @NonNull ExecuteAppFunctionResponse result) { + mLoggerWrapper.logAppFunctionSuccess(requestInternal, result, + callingUid); + } + + @Override + public void finalizeOnError(@NonNull AppFunctionException error) { + mLoggerWrapper.logAppFunctionError(requestInternal, + error.getErrorCode(), callingUid); + } + }); String validatedCallingPackage; try { @@ -162,9 +184,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { return null; } - int callingUid = Binder.getCallingUid(); - int callingPid = Binder.getCallingPid(); - ICancellationSignal localCancelTransport = CancellationSignal.createTransport(); THREAD_POOL_EXECUTOR.execute( diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java new file mode 100644 index 000000000000..b59915aa6343 --- /dev/null +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appfunctions; + +import static com.android.server.appfunctions.AppFunctionExecutors.LOGGING_THREAD_EXECUTOR; + +import android.annotation.NonNull; +import android.app.appfunctions.ExecuteAppFunctionAidlRequest; +import android.app.appfunctions.ExecuteAppFunctionResponse; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.SystemClock; +import android.util.Slog; + +import java.util.Objects; + +/** Wraps AppFunctionsStatsLog. */ +public class AppFunctionsLoggerWrapper { + private static final String TAG = AppFunctionsLoggerWrapper.class.getSimpleName(); + + private static final int SUCCESS_RESPONSE_CODE = -1; + + private final Context mContext; + + public AppFunctionsLoggerWrapper(@NonNull Context context) { + mContext = Objects.requireNonNull(context); + } + + void logAppFunctionSuccess(ExecuteAppFunctionAidlRequest request, + ExecuteAppFunctionResponse response, int callingUid) { + logAppFunctionsRequestReported(request, SUCCESS_RESPONSE_CODE, + response.getResponseDataSize(), callingUid); + } + + void logAppFunctionError(ExecuteAppFunctionAidlRequest request, int errorCode, int callingUid) { + logAppFunctionsRequestReported(request, errorCode, /* responseSizeBytes = */ 0, callingUid); + } + + private void logAppFunctionsRequestReported(ExecuteAppFunctionAidlRequest request, + int errorCode, int responseSizeBytes, int callingUid) { + final long latency = SystemClock.elapsedRealtime() - request.getRequestTime(); + LOGGING_THREAD_EXECUTOR.execute(() -> AppFunctionsStatsLog.write( + AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED, + callingUid, + getPackageUid(request.getClientRequest().getTargetPackageName()), + errorCode, + request.getClientRequest().getRequestDataSize(), responseSizeBytes, + latency) + ); + } + + private int getPackageUid(String packageName) { + try { + return mContext.getPackageManager().getPackageUid(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Package uid not found for " + packageName); + } + return 0; + } +} diff --git a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java index c689bb92f8f7..896c0fc51683 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java +++ b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java @@ -16,8 +16,8 @@ package com.android.server.appfunctions; import android.annotation.NonNull; -import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.AppFunctionException; +import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.ExecuteAppFunctionResponse; import android.app.appfunctions.IAppFunctionService; import android.app.appfunctions.ICancellationCallback; 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/companion/java/com/android/server/companion/BackupRestoreProcessor.java b/services/companion/java/com/android/server/companion/BackupRestoreProcessor.java index 4bcfb33b9e7c..7c8604f06b10 100644 --- a/services/companion/java/com/android/server/companion/BackupRestoreProcessor.java +++ b/services/companion/java/com/android/server/companion/BackupRestoreProcessor.java @@ -240,9 +240,9 @@ class BackupRestoreProcessor { boolean matchesMacAddress = Objects.equals( associationInfo.getDeviceMacAddress(), restored.getDeviceMacAddress()); - boolean matchesDeviceId = !Flags.associationTag() - || (associationInfo.getDeviceId() != null - && associationInfo.getDeviceId().isSameDevice(restored.getDeviceId())); + boolean matchesDeviceId = Flags.associationTag() + && (associationInfo.getDeviceId() != null + && associationInfo.getDeviceId().isSameDevice(restored.getDeviceId())); return matchesMacAddress || matchesDeviceId; }; AssociationInfo local = CollectionUtils.find(localAssociations, isSameDevice); diff --git a/services/core/Android.bp b/services/core/Android.bp index 371306f38a24..b3d85f8aac48 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -158,8 +158,8 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.gnss-V2-java", "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", @@ -246,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/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/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 3ce645158fe4..719928b8e582 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2846,6 +2846,14 @@ public class AccountManagerService : AccountsDb.DEBUG_ACTION_SET_PASSWORD; logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid); + + FrameworkStatsLog.write( + FrameworkStatsLog.ACCOUNT_MANAGER_EVENT, + account.type, + callingUid, + TextUtils.isEmpty(password) + ? FrameworkStatsLog.ACCOUNT_MANAGER_EVENT__EVENT_TYPE__PASSWORD_REMOVED + : FrameworkStatsLog.ACCOUNT_MANAGER_EVENT__EVENT_TYPE__PASSWORD_CHANGED); } } finally { accounts.accountsDb.endTransaction(); @@ -2912,7 +2920,7 @@ public class AccountManagerService if (!accountExistsCache(accounts, account)) { return; } - setUserdataInternal(accounts, account, key, value); + setUserdataInternal(accounts, account, key, value, callingUid); } finally { restoreCallingIdentity(identityToken); } @@ -2932,7 +2940,7 @@ public class AccountManagerService } private void setUserdataInternal(UserAccounts accounts, Account account, String key, - String value) { + String value, int callingUid) { synchronized (accounts.dbLock) { accounts.accountsDb.beginTransaction(); try { @@ -2958,6 +2966,11 @@ public class AccountManagerService AccountManager.invalidateLocalAccountUserDataCaches(); } } + FrameworkStatsLog.write( + FrameworkStatsLog.ACCOUNT_MANAGER_EVENT, + account.type, + callingUid, + FrameworkStatsLog.ACCOUNT_MANAGER_EVENT__EVENT_TYPE__USER_DATA_CHANGED); } private void onResult(IAccountManagerResponse response, Bundle result) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ebe7fa5e5a3f..cd929c1883d0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -361,6 +361,8 @@ import android.os.WorkSource; import android.os.incremental.IIncrementalService; import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalMetrics; +import android.os.instrumentation.IOffsetCallback; +import android.os.instrumentation.MethodDescriptor; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.DeviceConfig; @@ -509,6 +511,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -2781,9 +2784,7 @@ public class ActivityManagerService extends IActivityManager.Stub mIsolatedAppBindArgs = new ArrayMap<>(1); // See b/79378449 about the following exemption. addServiceToMap(mIsolatedAppBindArgs, "package"); - if (!android.server.Flags.removeJavaServiceManagerCache()) { - addServiceToMap(mIsolatedAppBindArgs, "permissionmgr"); - } + addServiceToMap(mIsolatedAppBindArgs, "permissionmgr"); } return mIsolatedAppBindArgs; } @@ -2794,38 +2795,27 @@ public class ActivityManagerService extends IActivityManager.Stub // Add common services. // IMPORTANT: Before adding services here, make sure ephemeral apps can access them too. // Enable the check in ApplicationThread.bindApplication() to make sure. - - // Removing User Service and App Ops Service from cache breaks boot for auto. - // Removing permissionmgr breaks tests for Android Auto due to SELinux restrictions. - // TODO: fix SELinux restrictions and remove caching for Android Auto. - if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) - || !android.server.Flags.removeJavaServiceManagerCache()) { - addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE); - addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE); - addServiceToMap(mAppBindArgs, Context.NETWORKMANAGEMENT_SERVICE); - addServiceToMap(mAppBindArgs, Context.CONNECTIVITY_SERVICE); - addServiceToMap(mAppBindArgs, Context.ACCESSIBILITY_SERVICE); - addServiceToMap(mAppBindArgs, Context.INPUT_METHOD_SERVICE); - addServiceToMap(mAppBindArgs, Context.INPUT_SERVICE); - addServiceToMap(mAppBindArgs, "graphicsstats"); - addServiceToMap(mAppBindArgs, "content"); - addServiceToMap(mAppBindArgs, Context.JOB_SCHEDULER_SERVICE); - addServiceToMap(mAppBindArgs, Context.NOTIFICATION_SERVICE); - addServiceToMap(mAppBindArgs, Context.VIBRATOR_SERVICE); - addServiceToMap(mAppBindArgs, Context.ACCOUNT_SERVICE); - addServiceToMap(mAppBindArgs, Context.POWER_SERVICE); - addServiceToMap(mAppBindArgs, "mount"); - addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE); - } - // See b/79378449 - // Getting the window service and package service binder from servicemanager - // is blocked for Apps. However they are necessary for apps. - // TODO: remove exception addServiceToMap(mAppBindArgs, "package"); - addServiceToMap(mAppBindArgs, Context.WINDOW_SERVICE); - addServiceToMap(mAppBindArgs, Context.USER_SERVICE); addServiceToMap(mAppBindArgs, "permissionmgr"); + addServiceToMap(mAppBindArgs, Context.WINDOW_SERVICE); + addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE); + addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE); + addServiceToMap(mAppBindArgs, Context.NETWORKMANAGEMENT_SERVICE); + addServiceToMap(mAppBindArgs, Context.CONNECTIVITY_SERVICE); + addServiceToMap(mAppBindArgs, Context.ACCESSIBILITY_SERVICE); + addServiceToMap(mAppBindArgs, Context.INPUT_METHOD_SERVICE); + addServiceToMap(mAppBindArgs, Context.INPUT_SERVICE); + addServiceToMap(mAppBindArgs, "graphicsstats"); addServiceToMap(mAppBindArgs, Context.APP_OPS_SERVICE); + addServiceToMap(mAppBindArgs, "content"); + addServiceToMap(mAppBindArgs, Context.JOB_SCHEDULER_SERVICE); + addServiceToMap(mAppBindArgs, Context.NOTIFICATION_SERVICE); + addServiceToMap(mAppBindArgs, Context.VIBRATOR_SERVICE); + addServiceToMap(mAppBindArgs, Context.ACCOUNT_SERVICE); + addServiceToMap(mAppBindArgs, Context.POWER_SERVICE); + addServiceToMap(mAppBindArgs, Context.USER_SERVICE); + addServiceToMap(mAppBindArgs, "mount"); + addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE); } return mAppBindArgs; } @@ -18055,6 +18045,26 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void getExecutableMethodFileOffsets(@NonNull String processName, + int pid, int uid, @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback callback) { + final IApplicationThread thread; + synchronized (ActivityManagerService.this) { + ProcessRecord record = mProcessList.getProcessRecordLocked(processName, uid); + if (record == null || record.getPid() != pid) { + throw new NoSuchElementException(); + } + thread = record.getThread(); + } + try { + thread.getExecutableMethodFileOffsets(methodDescriptor, callback); + } catch (RemoteException e) { + throw new RuntimeException( + "IApplicationThread.getExecutableMethodFileOffsets failed", e); + } + } + + @Override public void addCreatorToken(Intent intent, String creatorPackage) { ActivityManagerService.this.addCreatorToken(intent, creatorPackage); } @@ -19406,7 +19416,7 @@ public class ActivityManagerService extends IActivityManager.Stub return createOrGetIntentCreatorToken(intent, key); } else { - throw new IllegalArgumentException("intent does not contain a creator token."); + return null; } } diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 05aeb42dbc9f..83276391493f 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -19,7 +19,6 @@ package com.android.server.am; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.os.Binder; @@ -41,7 +40,6 @@ public final class BroadcastFilter extends IntentFilter { * ({@link IntentFilter#SYSTEM_LOW_PRIORITY}, {@link IntentFilter#SYSTEM_HIGH_PRIORITY}). */ @ChangeId - @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE) @VisibleForTesting static final long RESTRICT_PRIORITY_VALUES = 371309185L; diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index a1ab1eea3d3e..8d0805d3fa13 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -43,7 +43,6 @@ import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; import android.app.BroadcastOptions.DeliveryGroupPolicy; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.Intent; @@ -86,7 +85,6 @@ final class BroadcastRecord extends Binder { * will only influence the order of broadcast delivery within the same process. */ @ChangeId - @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE) @VisibleForTesting static final long LIMIT_PRIORITY_SCOPE = 371307720L; diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 6f83d0c75edf..87f87c76725e 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -143,6 +143,7 @@ public class SettingsToPropertiesMapper { "tv_os", "aaos_carframework_triage", "aaos_performance_triage", + "aaos_input_triage", "aaos_user_triage", "aaos_window_triage", "aaos_audio_triage", @@ -216,6 +217,7 @@ public class SettingsToPropertiesMapper { "pixel_bluetooth", "pixel_connectivity_gps", "pixel_continuity", + "pixel_display", "pixel_perf", "pixel_sensors", "pixel_state_server", 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/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 34d4fb02ad99..acb46d9b85e6 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -793,6 +793,7 @@ public class AudioDeviceInventory { * (see AudioService.onAudioServerDied() method) */ // Always executed on AudioDeviceBroker message queue + @GuardedBy("mDeviceBroker.mDeviceStateLock") /*package*/ void onRestoreDevices() { synchronized (mDevicesLock) { int res; @@ -815,6 +816,9 @@ public class AudioDeviceInventory { "Device inventory restore failed to reconnect " + di, EventLogger.Event.ALOGE, TAG); mConnectedDevices.remove(di.getKey(), di); + if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) { + mDeviceBroker.onSetBtScoActiveDevice(null); + } } } mAppliedStrategyRolesInt.clear(); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5928f8105cdf..1799b7715e5c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4177,6 +4177,12 @@ public class AudioService extends IAudioService.Stub // Stream mute changed, fire the intent. Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION); intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, isMuted); + if (replaceStreamBtSco() && isStreamBluetoothSco(streamType)) { + intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + AudioSystem.STREAM_BLUETOOTH_SCO); + // in this case broadcast for both sco and voice_call streams the mute status + sendBroadcastToAll(intent, null /* options */); + } intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); sendBroadcastToAll(intent, null /* options */); } @@ -4684,6 +4690,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 +4707,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 +4940,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 +4949,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 +4977,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 +4988,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); } @@ -9659,9 +9676,16 @@ public class AudioService extends IAudioService.Stub mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); - - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, - mStreamType); + int extraStreamType = mStreamType; + // TODO: remove this when deprecating STREAM_BLUETOOTH_SCO + if (isStreamBluetoothSco(mStreamType)) { + mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + AudioSystem.STREAM_BLUETOOTH_SCO); + extraStreamType = AudioSystem.STREAM_BLUETOOTH_SCO; + } else { + mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + mStreamType); + } mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS, streamAlias); @@ -9672,9 +9696,21 @@ public class AudioService extends IAudioService.Stub " aliased streams: " + aliasStreamIndexes; } AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent( - mStreamType, aliasStreamIndexesString, index, oldIndex)); + extraStreamType, aliasStreamIndexesString, index, oldIndex)); + if (extraStreamType != mStreamType) { + AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent( + mStreamType, aliasStreamIndexesString, index, oldIndex)); + } } sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions); + if (extraStreamType != mStreamType) { + // send multiple intents in case we merged voice call and bt sco streams + mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + mStreamType); + // do not use the options in thid case which could discard + // the previous intent + sendBroadcastToAll(mVolumeChanged, null); + } } } } 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/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 5c6299559856..0b633bd9c549 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -47,6 +47,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.ROOT_UID; import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS; +import static android.provider.Settings.Secure.MIRROR_BUILT_IN_DISPLAY; import static android.provider.Settings.Secure.RESOLUTION_MODE_FULL; import static android.provider.Settings.Secure.RESOLUTION_MODE_HIGH; import static android.provider.Settings.Secure.RESOLUTION_MODE_UNKNOWN; @@ -71,6 +72,7 @@ import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -534,6 +536,8 @@ public final class DisplayManagerService extends SystemService { private final boolean mExtraDisplayEventLogging; private final String mExtraDisplayLoggingPackageName; + private boolean mMirrorBuiltInDisplay; + private final BroadcastReceiver mIdleModeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -782,7 +786,11 @@ public final class DisplayManagerService extends SystemService { } dpc.onSwitchUser(newUserId, userSerial, newBrightness); }); - handleSettingsChange(); + handleMinimalPostProcessingAllowedSettingChange(); + + if (mFlags.isDisplayContentModeManagementEnabled()) { + updateMirrorBuiltInDisplaySettingLocked(); + } } } @@ -825,12 +833,15 @@ public final class DisplayManagerService extends SystemService { // relevant configuration should be in place. recordTopInsetLocked(mLogicalDisplayMapper.getDisplayLocked(Display.DEFAULT_DISPLAY)); - updateSettingsLocked(); + updateMinimalPostProcessingAllowedSettingLocked(); updateUserDisabledHdrTypesFromSettingsLocked(); updateUserPreferredDisplayModeSettingsLocked(); if (mIsHdrOutputControlEnabled) { updateHdrConversionModeSettingsLocked(); } + if (mFlags.isDisplayContentModeManagementEnabled()) { + updateMirrorBuiltInDisplaySettingLocked(); + } } mDisplayModeDirector.setDesiredDisplayModeSpecsListener( @@ -1180,27 +1191,61 @@ public final class DisplayManagerService extends SystemService { mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor( Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED), false, this); + + if (mFlags.isDisplayContentModeManagementEnabled()) { + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor( + MIRROR_BUILT_IN_DISPLAY), false, this, UserHandle.USER_ALL); + } } @Override public void onChange(boolean selfChange, Uri uri) { - handleSettingsChange(); + if (Settings.Secure.getUriFor( + Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED).equals(uri)) { + handleMinimalPostProcessingAllowedSettingChange(); + return; + } + + if (Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY).equals(uri)) { + if (mFlags.isDisplayContentModeManagementEnabled()) { + updateMirrorBuiltInDisplaySettingLocked(); + } + return; + } } } - private void handleSettingsChange() { + private void handleMinimalPostProcessingAllowedSettingChange() { synchronized (mSyncRoot) { - updateSettingsLocked(); + updateMinimalPostProcessingAllowedSettingLocked(); scheduleTraversalLocked(false); } } - private void updateSettingsLocked() { + private void updateMinimalPostProcessingAllowedSettingLocked() { setMinimalPostProcessingAllowed(Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED, 1, UserHandle.USER_CURRENT) != 0); } + private void updateMirrorBuiltInDisplaySettingLocked() { + if (!mFlags.isDisplayContentModeManagementEnabled()) { + Slog.e(TAG, "MirrorBuiltInDisplay setting shouldn't be updated when the flag is off."); + return; + } + + synchronized (mSyncRoot) { + ContentResolver resolver = mContext.getContentResolver(); + final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver, + MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0; + if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) { + return; + } + mMirrorBuiltInDisplay = mirrorBuiltInDisplay; + } + } + private void restoreResolutionFromBackup() { int savedMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.SCREEN_RESOLUTION_MODE, @@ -1997,7 +2042,7 @@ public final class DisplayManagerService extends SystemService { // handles stopping the projection. Slog.w(TAG, "Content Recording: failed to start mirroring - " + "releasing virtual display " + displayId); - releaseVirtualDisplayInternal(callback.asBinder(), callingUid); + releaseVirtualDisplayInternal(callback.asBinder()); return Display.INVALID_DISPLAY; } else if (projection != null) { // Indicate that this projection has been used to record, and can't be used @@ -2086,7 +2131,7 @@ public final class DisplayManagerService extends SystemService { // Something weird happened and the logical display was not created. Slog.w(TAG, "Rejecting request to create virtual display " + "because the logical display was not created."); - mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder(), callingUid); + mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder()); mDisplayDeviceRepo.onDisplayDeviceEvent(device, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED); return -1; @@ -2113,14 +2158,14 @@ public final class DisplayManagerService extends SystemService { } } - private void releaseVirtualDisplayInternal(IBinder appToken, int callingUid) { + private void releaseVirtualDisplayInternal(IBinder appToken) { synchronized (mSyncRoot) { if (mVirtualDisplayAdapter == null) { return; } DisplayDevice device = - mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken, callingUid); + mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken); Slog.d(TAG, "Virtual Display: Display Device released"); if (device != null) { // TODO: multi-display - handle virtual displays the same as other display adapters. @@ -4744,10 +4789,9 @@ public final class DisplayManagerService extends SystemService { @Override // Binder call public void releaseVirtualDisplay(IVirtualDisplayCallback callback) { - final int callingUid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - releaseVirtualDisplayInternal(callback.asBinder(), callingUid); + releaseVirtualDisplayInternal(callback.asBinder()); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 945365dcf8fe..f48fbea64f65 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -906,6 +906,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mLogicalDisplay.getPowerThrottlingDataIdLocked(); mHandler.postAtTime(() -> { + if (mStopped) { + // DPC has already stopped, don't execute any more. + return; + } + boolean changed = false; if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) { @@ -3306,7 +3311,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call int displayId, SensorManager sensorManager) { return new DisplayPowerProximityStateController(wakelockController, displayDeviceConfig, looper, nudgeUpdatePowerState, - displayId, sensorManager, /* injector= */ null); + displayId, sensorManager); } AutomaticBrightnessController getAutomaticBrightnessController( diff --git a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java index 215932ca19be..35455c841c7b 100644 --- a/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java +++ b/services/core/java/com/android/server/display/DisplayPowerProximityStateController.java @@ -16,6 +16,8 @@ package com.android.server.display; +import android.annotation.IntDef; +import android.annotation.Nullable; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -34,6 +36,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.utils.SensorUtils; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Maintains the proximity state of the display. @@ -42,18 +46,26 @@ import java.io.PrintWriter; */ public final class DisplayPowerProximityStateController { @VisibleForTesting - static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 1; - @VisibleForTesting static final int PROXIMITY_UNKNOWN = -1; + private static final int PROXIMITY_NEGATIVE = 0; @VisibleForTesting static final int PROXIMITY_POSITIVE = 1; + + @IntDef(prefix = { "PROXIMITY_" }, value = { + PROXIMITY_UNKNOWN, + PROXIMITY_NEGATIVE, + PROXIMITY_POSITIVE + }) + @Retention(RetentionPolicy.SOURCE) + @interface ProximityState {} + + @VisibleForTesting + static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 1; @VisibleForTesting static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0; private static final int MSG_IGNORE_PROXIMITY = 2; - private static final int PROXIMITY_NEGATIVE = 0; - private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; // Proximity sensor debounce delay in milliseconds for positive transitions. @@ -73,7 +85,7 @@ public final class DisplayPowerProximityStateController { private final DisplayPowerProximityStateHandler mHandler; // A runnable to execute the utility to update the power state. private final Runnable mNudgeUpdatePowerState; - private Clock mClock; + private final Clock mClock; // A listener which listen's to the events emitted by the proximity sensor. private final SensorEventListener mProximitySensorListener = new SensorEventListener() { @Override @@ -117,9 +129,6 @@ public final class DisplayPowerProximityStateController { // with the sensor manager. private boolean mProximitySensorEnabled; - // The raw non-debounced proximity sensor state. - private int mPendingProximity = PROXIMITY_UNKNOWN; - // -1 if fully debounced. Else, represents the time in ms when the debounce suspend blocker will // be removed. Applies for both positive and negative proximity flips. private long mPendingProximityDebounceTime = -1; @@ -128,8 +137,11 @@ public final class DisplayPowerProximityStateController { // When the screen turns on again, we report user activity to the power manager. private boolean mScreenOffBecauseOfProximity; + // The raw non-debounced proximity sensor state. + private @ProximityState int mPendingProximity = PROXIMITY_UNKNOWN; + // The debounced proximity sensor state. - private int mProximity = PROXIMITY_UNKNOWN; + private @ProximityState int mProximity = PROXIMITY_UNKNOWN; // The actual proximity sensor threshold value. private float mProximityThreshold; @@ -139,7 +151,7 @@ public final class DisplayPowerProximityStateController { private boolean mSkipRampBecauseOfProximityChangeToNegative = false; // The DisplayId of the associated Logical Display. - private int mDisplayId; + private final int mDisplayId; /** * Create a new instance of DisplayPowerProximityStateController. @@ -152,11 +164,18 @@ public final class DisplayPowerProximityStateController { * @param displayId The DisplayId of the associated Logical Display. * @param sensorManager The manager which lets us access the display's ProximitySensor */ - public DisplayPowerProximityStateController( - WakelockController wakeLockController, DisplayDeviceConfig displayDeviceConfig, - Looper looper, + public DisplayPowerProximityStateController(WakelockController wakeLockController, + DisplayDeviceConfig displayDeviceConfig, Looper looper, + Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager) { + this(wakeLockController, displayDeviceConfig, looper, nudgeUpdatePowerState, displayId, + sensorManager, new Injector()); + } + + @VisibleForTesting + DisplayPowerProximityStateController(WakelockController wakeLockController, + DisplayDeviceConfig displayDeviceConfig, Looper looper, Runnable nudgeUpdatePowerState, int displayId, SensorManager sensorManager, - Injector injector) { + @Nullable Injector injector) { if (injector == null) { injector = new Injector(); } @@ -437,7 +456,7 @@ public final class DisplayPowerProximityStateController { if (mProximity != mPendingProximity) { // if the status of the sensor changed, stop ignoring. mIgnoreProximityUntilChanged = false; - Slog.i(mTag, "No longer ignoring proximity [" + mPendingProximity + "]"); + Slog.i(mTag, "Applying proximity: " + proximityToString(mPendingProximity)); } // Sensor reading accepted. Apply the change then release the wake lock. mProximity = mPendingProximity; @@ -478,7 +497,7 @@ public final class DisplayPowerProximityStateController { } } - private String proximityToString(int state) { + private String proximityToString(@ProximityState int state) { switch (state) { case PROXIMITY_UNKNOWN: return "Unknown"; @@ -518,12 +537,12 @@ public final class DisplayPowerProximityStateController { } @VisibleForTesting - int getPendingProximity() { + @ProximityState int getPendingProximity() { return mPendingProximity; } @VisibleForTesting - int getProximity() { + @ProximityState int getProximity() { return mProximity; } @@ -550,7 +569,7 @@ public final class DisplayPowerProximityStateController { @VisibleForTesting static class Injector { Clock createClock() { - return () -> SystemClock.uptimeMillis(); + return SystemClock::uptimeMillis; } } } diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index c0903a9bafac..79592a656409 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -506,9 +506,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { return; } - Slog.i(TAG, "Requesting Transition to state: " + state.getIdentifier() + ", from state=" - + mDeviceState.getIdentifier() + ", interactive=" + mInteractive - + ", mBootCompleted=" + mBootCompleted); // As part of a state transition, we may need to turn off some displays temporarily so that // the transition is smooth. Plus, on some devices, only one internal displays can be // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be @@ -522,6 +519,11 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final boolean sleepDevice = shouldDeviceBePutToSleep(mPendingDeviceState, mDeviceState, mInteractive, mBootCompleted); + Slog.i(TAG, "Requesting Transition to state: " + state.getIdentifier() + ", from state=" + + mDeviceState.getIdentifier() + ", interactive=" + mInteractive + + ", mBootCompleted=" + mBootCompleted + ", wakeDevice=" + wakeDevice + + ", sleepDevice=" + sleepDevice); + // If all displays are off already, we can just transition here, unless we are trying to // wake or sleep the device as part of this transition. In that case defer the final // transition until later once the device is awake/asleep. diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 836f4ede8f57..f14e452ab8d3 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -91,6 +91,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter { private final ArrayMap<IBinder, VirtualDisplayDevice> mVirtualDisplayDevices = new ArrayMap<>(); + // When a virtual display is created, the mapping (appToken -> ownerUid) is stored here. That + // way, when the display is released later, we can retrieve the ownerUid and decrement + // the number of virtual displays that exist for that ownerUid. We can't use + // Binder.getCallingUid() because the display might be released by the system process and not + // the process that created the display. + private final ArrayMap<IBinder, Integer> mOwnerUids = new ArrayMap<>(); + private final int mMaxDevices; private final int mMaxDevicesPerPackage; private final SparseIntArray mNoOfDevicesPerPackage = new SparseIntArray(); @@ -194,6 +201,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mVirtualDisplayDevices.put(appToken, device); if (getFeatureFlags().isVirtualDisplayLimitEnabled()) { mNoOfDevicesPerPackage.put(ownerUid, noOfDevices + 1); + mOwnerUids.put(appToken, ownerUid); } try { @@ -205,7 +213,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { appToken.linkToDeath(device, 0); } catch (RemoteException ex) { Slog.e(TAG, "Virtual Display: error while setting up VirtualDisplayDevice", ex); - removeVirtualDisplayDeviceLocked(appToken, ownerUid); + removeVirtualDisplayDeviceLocked(appToken); device.destroyLocked(false); return null; } @@ -252,12 +260,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { /** * Release a virtual display that was previously created * @param appToken The token to identify the display - * @param ownerUid The UID of the package, used to keep track of and limit the number of - * displays created per package * @return The display device that has been removed */ - public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken, int ownerUid) { - VirtualDisplayDevice device = removeVirtualDisplayDeviceLocked(appToken, ownerUid); + public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) { + VirtualDisplayDevice device = removeVirtualDisplayDeviceLocked(appToken); if (device != null) { Slog.v(TAG, "Release VirtualDisplay " + device.mName); device.destroyLocked(true); @@ -299,11 +305,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter { } } - private VirtualDisplayDevice removeVirtualDisplayDeviceLocked(IBinder appToken, int ownerUid) { - int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0); + private VirtualDisplayDevice removeVirtualDisplayDeviceLocked(IBinder appToken) { if (getFeatureFlags().isVirtualDisplayLimitEnabled()) { + int ownerUid = mOwnerUids.get(appToken); + int noOfDevices = mNoOfDevicesPerPackage.get(ownerUid, /* valueIfKeyNotFound= */ 0); if (noOfDevices <= 1) { mNoOfDevicesPerPackage.delete(ownerUid); + mOwnerUids.remove(appToken); } else { mNoOfDevicesPerPackage.put(ownerUid, noOfDevices - 1); } @@ -378,7 +386,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { @Override public void binderDied() { synchronized (getSyncRoot()) { - removeVirtualDisplayDeviceLocked(mAppToken, mOwnerUid); + removeVirtualDisplayDeviceLocked(mAppToken); Slog.i(TAG, "Virtual display device released because application token died: " + mOwnerPackageName); destroyLocked(false); diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index 45106f54cb9f..78bd41bd2e11 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -93,6 +93,10 @@ public class DisplayManagerFlags { com.android.graphics.surfaceflinger.flags.Flags.FLAG_ENABLE_SMALL_AREA_DETECTION, com.android.graphics.surfaceflinger.flags.Flags::enableSmallAreaDetection); + private final FlagState mDisplayConfigErrorHalFlagState = new FlagState( + com.android.graphics.surfaceflinger.flags.Flags.FLAG_DISPLAY_CONFIG_ERROR_HAL, + com.android.graphics.surfaceflinger.flags.Flags::displayConfigErrorHal); + private final FlagState mBrightnessIntRangeUserPerceptionFlagState = new FlagState( Flags.FLAG_BRIGHTNESS_INT_RANGE_USER_PERCEPTION, Flags::brightnessIntRangeUserPerception); @@ -256,6 +260,10 @@ public class DisplayManagerFlags { Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS, Flags::displayListenerPerformanceImprovements ); + private final FlagState mEnableDisplayContentModeManagementFlagState = new FlagState( + Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT, + Flags::enableDisplayContentModeManagement + ); private final FlagState mSubscribeGranularDisplayEvents = new FlagState( Flags.FLAG_SUBSCRIBE_GRANULAR_DISPLAY_EVENTS, @@ -357,6 +365,10 @@ public class DisplayManagerFlags { return mSmallAreaDetectionFlagState.isEnabled(); } + public boolean isDisplayConfigErrorHalEnabled() { + return mDisplayConfigErrorHalFlagState.isEnabled(); + } + public boolean isBrightnessIntRangeUserPerceptionEnabled() { return mBrightnessIntRangeUserPerceptionFlagState.isEnabled(); } @@ -556,6 +568,10 @@ public class DisplayManagerFlags { return mDisplayListenerPerformanceImprovementsFlagState.isEnabled(); } + public boolean isDisplayContentModeManagementEnabled() { + return mEnableDisplayContentModeManagementFlagState.isEnabled(); + } + /** * @return {@code true} if the flag for subscribing to granular display events is enabled */ @@ -583,6 +599,7 @@ public class DisplayManagerFlags { pw.println(" " + mPowerThrottlingClamperFlagState); pw.println(" " + mEvenDimmerFlagState); pw.println(" " + mSmallAreaDetectionFlagState); + pw.println(" " + mDisplayConfigErrorHalFlagState); pw.println(" " + mBrightnessIntRangeUserPerceptionFlagState); pw.println(" " + mRestrictDisplayModes); pw.println(" " + mBrightnessWearBedtimeModeClamperFlagState); @@ -618,6 +635,7 @@ public class DisplayManagerFlags { pw.println(" " + mEnablePluginManagerFlagState); pw.println(" " + mDisplayListenerPerformanceImprovementsFlagState); pw.println(" " + mSubscribeGranularDisplayEvents); + pw.println(" " + mEnableDisplayContentModeManagementFlagState); } private static class FlagState { diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 8423e1911764..02e2882442bf 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -136,6 +136,7 @@ public class DisplayModeDirector { private final ProximitySensorObserver mSensorObserver; private final HbmObserver mHbmObserver; private final SkinThermalStatusObserver mSkinThermalStatusObserver; + private final ModeChangeObserver mModeChangeObserver; @Nullable private final SystemRequestObserver mSystemRequestObserver; @@ -247,6 +248,7 @@ public class DisplayModeDirector { mDisplayObserver = new DisplayObserver(context, handler, mVotesStorage, injector); mSensorObserver = new ProximitySensorObserver(mVotesStorage, injector); mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, mVotesStorage); + mModeChangeObserver = new ModeChangeObserver(mVotesStorage, injector, handler.getLooper()); mHbmObserver = new HbmObserver(injector, mVotesStorage, BackgroundThread.getHandler(), mDeviceConfigDisplaySettings); if (displayManagerFlags.isRestrictDisplayModesEnabled()) { @@ -275,6 +277,9 @@ public class DisplayModeDirector { mSensorObserver.observe(); mHbmObserver.observe(); mSkinThermalStatusObserver.observe(); + if (mDisplayManagerFlags.isDisplayConfigErrorHalEnabled()) { + mModeChangeObserver.observe(); + } synchronized (mLock) { // We may have a listener already registered before the call to start, so go ahead and // notify them to pick up our newly initialized state. diff --git a/services/core/java/com/android/server/display/mode/ModeChangeObserver.java b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java new file mode 100644 index 000000000000..bbc13cc6ae7e --- /dev/null +++ b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.mode; + +import android.os.Looper; +import android.util.Slog; +import android.util.SparseArray; +import android.view.Display; +import android.view.DisplayAddress; +import android.view.DisplayEventReceiver; + +import com.android.internal.annotations.KeepForWeakReference; + +import java.util.HashSet; +import java.util.Set; + +final class ModeChangeObserver { + private static final String TAG = "ModeChangeObserver"; + + private final VotesStorage mVotesStorage; + private final DisplayModeDirector.Injector mInjector; + + @SuppressWarnings("unused") + @KeepForWeakReference + private DisplayEventReceiver mModeChangeListener; + private final SparseArray<Set<Integer>> mRejectedModesByDisplay = new SparseArray<>(); + private Looper mLooper; + + ModeChangeObserver(VotesStorage votesStorage, DisplayModeDirector.Injector injector, + Looper looper) { + mVotesStorage = votesStorage; + mInjector = injector; + mLooper = looper; + } + + void observe() { + mModeChangeListener = new DisplayEventReceiver(mLooper) { + @Override + public void onModeRejected(long physicalDisplayId, int modeId) { + Slog.d(TAG, "Mode Rejected event received"); + int displayId = getLogicalDisplayId(physicalDisplayId); + if (displayId < 0) { + Slog.e(TAG, "Logical Display Id not found"); + return; + } + populateRejectedModesListByDisplay(displayId, modeId); + } + + @Override + public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { + Slog.d(TAG, "Hotplug event received"); + if (!connected) { + int displayId = getLogicalDisplayId(physicalDisplayId); + if (displayId < 0) { + Slog.e(TAG, "Logical Display Id not found"); + return; + } + clearRejectedModesListByDisplay(displayId); + } + } + }; + } + + private int getLogicalDisplayId(long rejectedModePhysicalDisplayId) { + Display[] displays = mInjector.getDisplays(); + + for (Display display : displays) { + DisplayAddress address = display.getAddress(); + if (address instanceof DisplayAddress.Physical physical) { + long physicalDisplayId = physical.getPhysicalDisplayId(); + if (physicalDisplayId == rejectedModePhysicalDisplayId) { + return display.getDisplayId(); + } + } + } + return -1; + } + + private void populateRejectedModesListByDisplay(int displayId, int rejectedModeId) { + Set<Integer> alreadyRejectedModes = mRejectedModesByDisplay.get(displayId); + if (alreadyRejectedModes == null) { + alreadyRejectedModes = new HashSet<>(); + mRejectedModesByDisplay.put(displayId, alreadyRejectedModes); + } + alreadyRejectedModes.add(rejectedModeId); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, + Vote.forRejectedModes(alreadyRejectedModes)); + } + + private void clearRejectedModesListByDisplay(int displayId) { + mRejectedModesByDisplay.remove(displayId); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, null); + } +} diff --git a/services/core/java/com/android/server/display/mode/RejectedModesVote.java b/services/core/java/com/android/server/display/mode/RejectedModesVote.java new file mode 100644 index 000000000000..db8c8527844b --- /dev/null +++ b/services/core/java/com/android/server/display/mode/RejectedModesVote.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.mode; + +import android.annotation.NonNull; + +import java.util.Collections; +import java.util.Set; + +public class RejectedModesVote implements Vote { + + final Set<Integer> mModeIds; + + RejectedModesVote(Set<Integer> modeIds) { + mModeIds = Collections.unmodifiableSet(modeIds); + } + @Override + public void updateSummary(@NonNull VoteSummary summary) { + summary.rejectedModeIds.addAll(mModeIds); + } + + @Override + public String toString() { + return "RejectedModesVote{ mModeIds=" + mModeIds + " }"; + } +} diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java index f5abb0561ce7..428ccedf8760 100644 --- a/services/core/java/com/android/server/display/mode/Vote.java +++ b/services/core/java/com/android/server/display/mode/Vote.java @@ -25,6 +25,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Set; interface Vote { // DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest @@ -82,68 +83,73 @@ interface Vote { int PRIORITY_APP_REQUEST_SIZE = 7; + // PRIORITY_REJECTED_MODES rejects the modes for which the mode config failed + // so that the modeset can be retried for next available mode after filtering + // out the rejected modes for the connected display + int PRIORITY_REJECTED_MODES = 8; + // PRIORITY_USER_SETTING_PEAK_REFRESH_RATE restricts physical refresh rate to // [0, max(PEAK, MIN)], depending on user settings peakRR/minRR values - int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 8; + int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 9; // PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE has a higher priority than // PRIORITY_USER_SETTING_PEAK_REFRESH_RATE and will limit render rate to [0, max(PEAK, MIN)] // in case physical refresh rate vote is discarded (due to other high priority votes), // render rate vote can still apply - int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 9; + int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 10; // Restrict all displays physical refresh rate to 60Hz when external display is connected. // It votes [59Hz, 61Hz]. - int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 10; + int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 11; // PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE has a higher priority than // PRIORITY_SYNCHRONIZED_REFRESH_RATE and will limit render rate to [59Hz, 61Hz]. // In case physical refresh rate vote discarded (due to physical refresh rate not supported), // render rate vote can still apply. - int PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE = 11; + int PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE = 12; // Restrict displays max available resolution and refresh rates. It votes [0, LIMIT] - int PRIORITY_LIMIT_MODE = 12; + int PRIORITY_LIMIT_MODE = 13; // To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh // rate to max value (same as for PRIORITY_UDFPS) on lock screen - int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 13; + int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 14; // For concurrent displays we want to limit refresh rate on all displays - int PRIORITY_LAYOUT_LIMITED_REFRESH_RATE = 14; + int PRIORITY_LAYOUT_LIMITED_REFRESH_RATE = 15; // For concurrent displays we want to limit refresh rate on all displays - int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 15; + int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 16; // For internal application to limit display modes to specific ids - int PRIORITY_SYSTEM_REQUESTED_MODES = 16; + int PRIORITY_SYSTEM_REQUESTED_MODES = 17; // PRIORITY_LOW_POWER_MODE_MODES limits display modes to specific refreshRate-vsync pairs if // Settings.Global.LOW_POWER_MODE is on. // Lower priority that PRIORITY_LOW_POWER_MODE_RENDER_RATE and if discarded (due to other // higher priority votes), render rate limit can still apply - int PRIORITY_LOW_POWER_MODE_MODES = 17; + int PRIORITY_LOW_POWER_MODE_MODES = 18; // PRIORITY_LOW_POWER_MODE_RENDER_RATE force the render frame rate to [0, 60HZ] if // Settings.Global.LOW_POWER_MODE is on. - int PRIORITY_LOW_POWER_MODE_RENDER_RATE = 18; + int PRIORITY_LOW_POWER_MODE_RENDER_RATE = 19; // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the // higher priority voters' result is a range, it will fix the rate to a single choice. // It's used to avoid refresh rate switches in certain conditions which may result in the // user seeing the display flickering when the switches occur. - int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 19; + int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 20; // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL. - int PRIORITY_SKIN_TEMPERATURE = 20; + int PRIORITY_SKIN_TEMPERATURE = 21; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. - int PRIORITY_PROXIMITY = 21; + int PRIORITY_PROXIMITY = 22; // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order // to function, so this needs to be the highest priority of all votes. - int PRIORITY_UDFPS = 22; + int PRIORITY_UDFPS = 23; @IntDef(prefix = { "PRIORITY_" }, value = { PRIORITY_DEFAULT_RENDER_FRAME_RATE, @@ -154,6 +160,7 @@ interface Vote { PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE, PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE, PRIORITY_APP_REQUEST_SIZE, + PRIORITY_REJECTED_MODES, PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, PRIORITY_SYNCHRONIZED_REFRESH_RATE, @@ -245,6 +252,10 @@ interface Vote { return new SupportedModesVote(modeIds); } + static Vote forRejectedModes(Set<Integer> modeIds) { + return new RejectedModesVote(modeIds); + } + static String priorityToString(int priority) { switch (priority) { case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE: @@ -253,6 +264,8 @@ interface Vote { return "PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE"; case PRIORITY_APP_REQUEST_SIZE: return "PRIORITY_APP_REQUEST_SIZE"; + case PRIORITY_REJECTED_MODES: + return "PRIORITY_REJECTED_MODES"; case PRIORITY_DEFAULT_RENDER_FRAME_RATE: return "PRIORITY_DEFAULT_REFRESH_RATE"; case PRIORITY_FLICKER_REFRESH_RATE: diff --git a/services/core/java/com/android/server/display/mode/VoteSummary.java b/services/core/java/com/android/server/display/mode/VoteSummary.java index 00a922630d8e..41664930fc2e 100644 --- a/services/core/java/com/android/server/display/mode/VoteSummary.java +++ b/services/core/java/com/android/server/display/mode/VoteSummary.java @@ -55,6 +55,11 @@ final class VoteSummary { @Nullable public List<Integer> supportedModeIds; + /** + * set of rejected modes due to mode config failure for connected display + */ + public Set<Integer> rejectedModeIds = new HashSet<>(); + final boolean mIsDisplayResolutionRangeVotingEnabled; private final boolean mSupportedModesVoteEnabled; @@ -132,6 +137,9 @@ final class VoteSummary { if (!validateModeSupported(mode)) { continue; } + if (!validateModeRejected(mode)) { + continue; + } if (!validateModeSize(mode)) { continue; } @@ -285,6 +293,22 @@ final class VoteSummary { return false; } + private boolean validateModeRejected(Display.Mode mode) { + if (rejectedModeIds == null) { + return true; + } + if (!rejectedModeIds.contains(mode.getModeId())) { + return true; + } + if (mLoggingEnabled) { + Slog.w(TAG, "Discarding mode" + mode.getModeId() + + ", is a rejectedMode" + + ": mode.modeId=" + mode.getModeId() + + ", rejectedModeIds=" + rejectedModeIds); + } + return false; + } + private boolean validateRefreshRatesSupported(Display.Mode mode) { if (supportedRefreshRates == null || !mSupportedModesVoteEnabled) { return true; @@ -397,6 +421,7 @@ final class VoteSummary { requestedRefreshRates.clear(); supportedRefreshRates = null; supportedModeIds = null; + rejectedModeIds.clear(); if (mLoggingEnabled) { Slog.i(TAG, "Summary reset: " + this); } @@ -421,6 +446,7 @@ final class VoteSummary { + ", requestRefreshRates=" + requestedRefreshRates + ", supportedRefreshRates=" + supportedRefreshRates + ", supportedModeIds=" + supportedModeIds + + ", rejectedModeIds=" + rejectedModeIds + ", mIsDisplayResolutionRangeVotingEnabled=" + mIsDisplayResolutionRangeVotingEnabled + ", mSupportedModesVoteEnabled=" + mSupportedModesVoteEnabled diff --git a/services/core/java/com/android/server/display/plugin/PluginEventStorage.java b/services/core/java/com/android/server/display/plugin/PluginEventStorage.java new file mode 100644 index 000000000000..c58ba556bcb6 --- /dev/null +++ b/services/core/java/com/android/server/display/plugin/PluginEventStorage.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.plugin; + +import android.util.IndentingPrintWriter; + +import com.android.internal.util.RingBuffer; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +class PluginEventStorage { + private static final long TIME_FRAME_LENGTH = 60_000; + private static final long MIN_EVENT_DELAY = 500; + private static final int MAX_TIME_FRAMES = 10; + // not thread safe + private static final SimpleDateFormat sDateFormat = new SimpleDateFormat( + "MM-dd HH:mm:ss.SSS", Locale.US); + + RingBuffer<TimeFrame> mEvents = new RingBuffer<>( + TimeFrame::new, TimeFrame[]::new, MAX_TIME_FRAMES); + + private final Map<PluginType<?>, Long> mEventTimes = new HashMap<>(); + private long mTimeFrameStart = 0; + private final Map<PluginType<?>, EventCounter> mCounters = new HashMap<>(); + + <T> void onValueUpdated(PluginType<T> type) { + long eventTime = System.currentTimeMillis(); + if (eventTime - TIME_FRAME_LENGTH > mTimeFrameStart) { // event is in next TimeFrame + closeCurrentTimeFrame(); + mTimeFrameStart = eventTime; + } + updateCurrentTimeFrame(type, eventTime); + } + + private void closeCurrentTimeFrame() { + if (!mCounters.isEmpty()) { + mEvents.append(new TimeFrame( + mTimeFrameStart, mTimeFrameStart + TIME_FRAME_LENGTH, mCounters)); + mCounters.clear(); + } + } + + private <T> void updateCurrentTimeFrame(PluginType<T> type, long eventTime) { + EventCounter counter = mCounters.get(type); + long previousTimestamp = mEventTimes.getOrDefault(type, 0L); + if (counter == null) { + counter = new EventCounter(); + mCounters.put(type, counter); + } + counter.increase(eventTime, previousTimestamp); + mEventTimes.put(type, eventTime); + } + + List<TimeFrame> getTimeFrames() { + List<TimeFrame> timeFrames = new ArrayList<>(Arrays.stream(mEvents.toArray()).toList()); + timeFrames.add(new TimeFrame( + mTimeFrameStart, System.currentTimeMillis(), mCounters)); + return timeFrames; + } + + static class TimeFrame { + private final long mStart; + private final long mEnd; + private final Map<PluginType<?>, EventCounter> mCounters; + + private TimeFrame() { + this(0, 0, Map.of()); + } + + private TimeFrame(long start, long end, Map<PluginType<?>, EventCounter> counters) { + mStart = start; + mEnd = end; + mCounters = new HashMap<>(counters); + } + + @SuppressWarnings("JavaUtilDate") + void dump(PrintWriter pw) { + pw.append("TimeFrame:[") + .append(sDateFormat.format(new Date(mStart))) + .append(" - ") + .append(sDateFormat.format(new Date(mEnd))) + .println("]:"); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + if (mCounters.isEmpty()) { + ipw.println("NO EVENTS"); + } else { + for (Map.Entry<PluginType<?>, EventCounter> entry: mCounters.entrySet()) { + ipw.append(entry.getKey().mName).append(" -> {"); + entry.getValue().dump(ipw); + ipw.println("}"); + } + } + } + } + + private static class EventCounter { + private int mEventCounter = 0; + private int mFastEventCounter = 0; + + private void increase(long timestamp, long previousTimestamp) { + mEventCounter++; + if (timestamp - previousTimestamp < MIN_EVENT_DELAY) { + mFastEventCounter++; + } + } + + private void dump(PrintWriter pw) { + pw.append("Count:").append(String.valueOf(mEventCounter)) + .append("; Fast:").append(String.valueOf(mFastEventCounter)); + } + } +} diff --git a/services/core/java/com/android/server/display/plugin/PluginStorage.java b/services/core/java/com/android/server/display/plugin/PluginStorage.java index 2bcea777e681..dd3415fb614d 100644 --- a/services/core/java/com/android/server/display/plugin/PluginStorage.java +++ b/services/core/java/com/android/server/display/plugin/PluginStorage.java @@ -25,6 +25,7 @@ import com.android.tools.r8.keepanno.annotations.KeepForApi; import java.io.PrintWriter; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -39,6 +40,8 @@ public class PluginStorage { private final Map<PluginType<?>, Object> mValues = new HashMap<>(); @GuardedBy("mLock") private final Map<PluginType<?>, ListenersContainer<?>> mListeners = new HashMap<>(); + @GuardedBy("mLock") + private final PluginEventStorage mPluginEventStorage = new PluginEventStorage(); /** * Updates value in storage and forwards it to corresponding listeners. @@ -50,6 +53,7 @@ public class PluginStorage { Set<PluginManager.PluginChangeListener<T>> localListeners; synchronized (mLock) { mValues.put(type, value); + mPluginEventStorage.onValueUpdated(type); ListenersContainer<T> container = getListenersContainerForTypeLocked(type); localListeners = new LinkedHashSet<>(container.mListeners); } @@ -91,13 +95,19 @@ public class PluginStorage { Map<PluginType<?>, Object> localValues; @SuppressWarnings("rawtypes") Map<PluginType, Set> localListeners = new HashMap<>(); + List<PluginEventStorage.TimeFrame> timeFrames; synchronized (mLock) { + timeFrames = mPluginEventStorage.getTimeFrames(); localValues = new HashMap<>(mValues); mListeners.forEach((type, container) -> localListeners.put(type, container.mListeners)); } pw.println("PluginStorage:"); pw.println("values=" + localValues); pw.println("listeners=" + localListeners); + pw.println("PluginEventStorage:"); + for (PluginEventStorage.TimeFrame timeFrame: timeFrames) { + timeFrame.dump(pw); + } } @GuardedBy("mLock") 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/ContextHubHalEndpointCallback.java b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java index 8e72553a9c52..9d52c6a020f4 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java @@ -68,7 +68,7 @@ public class ContextHubHalEndpointCallback } HubEndpointInfo[] endpointInfos = new HubEndpointInfo[halEndpointInfos.length]; for (int i = 0; i < halEndpointInfos.length; i++) { - endpointInfos[i++] = new HubEndpointInfo(halEndpointInfos[i]); + endpointInfos[i] = new HubEndpointInfo(halEndpointInfos[i]); } mEndpointLifecycleCallback.onEndpointStarted(endpointInfos); } 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/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index db1e6b465ff8..5ee9452c6a53 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -66,6 +66,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { private final int mUserId; private final Handler mHandler; private final boolean mIsSelfScanOnlyProvider; + private final boolean mSupportsSystemMediaRouting; private final ServiceConnection mServiceConnection = new ServiceConnectionImpl(); // Connection state @@ -95,12 +96,14 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { @NonNull Looper looper, @NonNull ComponentName componentName, boolean isSelfScanOnlyProvider, + boolean supportsSystemMediaRouting, int userId) { super(componentName, /* isSystemRouteProvider= */ false); mContext = Objects.requireNonNull(context, "Context must not be null."); mRequestIdToSessionCreationRequest = new LongSparseArray<>(); mSessionOriginalIdToTransferRequest = new HashMap<>(); mIsSelfScanOnlyProvider = isSelfScanOnlyProvider; + mSupportsSystemMediaRouting = supportsSystemMediaRouting; mUserId = userId; mHandler = new Handler(looper); } @@ -651,11 +654,12 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { } return TextUtils.formatSimple( "ProviderServiceProxy - package: %s, bound: %b, connection (active:%b, ready:%b), " - + "pending (session creations: %d, transfers: %d)", + + "system media=%b, pending (session creations: %d, transfers: %d)", mComponentName.getPackageName(), mBound, mActiveConnection != null, mConnectionReady, + mSupportsSystemMediaRouting, pendingSessionCreationCount, pendingTransferCount); } @@ -697,7 +701,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { Connection(IMediaRoute2ProviderService serviceBinder) { mService = serviceBinder; - mCallbackStub = new ServiceCallbackStub(this); + mCallbackStub = new ServiceCallbackStub(this, mSupportsSystemMediaRouting); } public boolean register() { @@ -811,9 +815,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { private static final class ServiceCallbackStub extends IMediaRoute2ProviderServiceCallback.Stub { private final WeakReference<Connection> mConnectionRef; + private final boolean mAllowSystemMediaRoutes; - ServiceCallbackStub(Connection connection) { + ServiceCallbackStub(Connection connection, boolean allowSystemMediaRoutes) { mConnectionRef = new WeakReference<>(connection); + mAllowSystemMediaRoutes = allowSystemMediaRoutes; } public void dispose() { @@ -846,6 +852,13 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider { + "Disallowed route: " + route); } + + if (route.supportsSystemMediaRouting() && !mAllowSystemMediaRoutes) { + throw new SecurityException( + "This provider is not allowed to publish routes that support system" + + " media routing. Disallowed route: " + + route); + } } Connection connection = mConnectionRef.get(); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java index 93ef6f044e1b..69c460e0f19d 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java @@ -17,7 +17,9 @@ package com.android.server.media; import static android.content.pm.PackageManager.GET_RESOLVED_FILTER; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import android.Manifest; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -130,22 +132,33 @@ final class MediaRoute2ProviderWatcher { ServiceInfo serviceInfo = resolveInfo.serviceInfo; if (serviceInfo != null) { boolean isSelfScanOnlyProvider = false; + boolean supportsSystemMediaRouting = false; Iterator<String> categoriesIterator = resolveInfo.filter.categoriesIterator(); if (categoriesIterator != null) { while (categoriesIterator.hasNext()) { + String category = categoriesIterator.next(); isSelfScanOnlyProvider |= - MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals( - categoriesIterator.next()); + MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals(category); + supportsSystemMediaRouting |= + MediaRoute2ProviderService.SERVICE_INTERFACE_SYSTEM_MEDIA.equals( + category); } } int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); if (sourceIndex < 0) { + supportsSystemMediaRouting &= Flags.enableMirroringInMediaRouter2(); + supportsSystemMediaRouting &= + mPackageManager.checkPermission( + Manifest.permission.MODIFY_AUDIO_ROUTING, + serviceInfo.packageName) + == PERMISSION_GRANTED; MediaRoute2ProviderServiceProxy proxy = new MediaRoute2ProviderServiceProxy( mContext, mHandler.getLooper(), new ComponentName(serviceInfo.packageName, serviceInfo.name), isSelfScanOnlyProvider, + supportsSystemMediaRouting, mUserId); Slog.i( TAG, diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index 849751b99aae..f363d5852354 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -31,7 +31,9 @@ import android.media.quality.PictureProfile; import android.media.quality.PictureProfileHandle; import android.media.quality.SoundProfile; import android.media.quality.SoundProfileHandle; +import android.os.Binder; import android.os.PersistableBundle; +import android.os.UserHandle; import android.util.Log; import com.android.server.SystemService; @@ -57,6 +59,7 @@ public class MediaQualityService extends SystemService { private static final boolean DEBUG = false; private static final String TAG = "MediaQualityService"; + private static final int MAX_UUID_GENERATION_ATTEMPTS = 10; private final Context mContext; private final MediaQualityDbHelper mMediaQualityDbHelper; private final BiMap<Long, String> mPictureProfileTempIdMap; @@ -81,15 +84,15 @@ public class MediaQualityService extends SystemService { private final class BinderService extends IMediaQualityManager.Stub { @Override - public PictureProfile createPictureProfile(PictureProfile pp, int userId) { + public PictureProfile createPictureProfile(PictureProfile pp, UserHandle user) { SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - ContentValues values = new ContentValues(); - values.put(BaseParameters.PARAMETER_TYPE, pp.getProfileType()); - values.put(BaseParameters.PARAMETER_NAME, pp.getName()); - values.put(BaseParameters.PARAMETER_PACKAGE, pp.getPackageName()); - values.put(BaseParameters.PARAMETER_INPUT_ID, pp.getInputId()); - values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(pp.getParameters())); + ContentValues values = getContentValues(null, + pp.getProfileType(), + pp.getName(), + pp.getPackageName(), + pp.getInputId(), + pp.getParameters()); // id is auto-generated by SQLite upon successful insertion of row Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, @@ -100,12 +103,23 @@ public class MediaQualityService extends SystemService { } @Override - public void updatePictureProfile(String id, PictureProfile pp, int userId) { - // TODO: implement + public void updatePictureProfile(String id, PictureProfile pp, UserHandle user) { + Long intId = mPictureProfileTempIdMap.inverse().get(id); + + ContentValues values = getContentValues(intId, + pp.getProfileType(), + pp.getName(), + pp.getPackageName(), + pp.getInputId(), + pp.getParameters()); + + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + db.replace(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + null, values); } @Override - public void removePictureProfile(String id, int userId) { + public void removePictureProfile(String id, UserHandle user) { Long intId = mPictureProfileTempIdMap.inverse().get(id); if (intId != null) { SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); @@ -118,7 +132,8 @@ public class MediaQualityService extends SystemService { } @Override - public PictureProfile getPictureProfile(int type, String name, int userId) { + public PictureProfile getPictureProfile(int type, String name, boolean includeParams, + UserHandle user) { String selection = BaseParameters.PARAMETER_TYPE + " = ? AND " + BaseParameters.PARAMETER_NAME + " = ?"; String[] selectionArguments = {Integer.toString(type), name}; @@ -144,7 +159,8 @@ public class MediaQualityService extends SystemService { } @Override - public List<PictureProfile> getPictureProfilesByPackage(String packageName, int userId) { + public List<PictureProfile> getPictureProfilesByPackage( + String packageName, boolean includeParams, UserHandle user) { String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; String[] selectionArguments = {packageName}; return getPictureProfilesBasedOnConditions(getAllMediaProfileColumns(), selection, @@ -152,18 +168,24 @@ public class MediaQualityService extends SystemService { } @Override - public List<PictureProfile> getAvailablePictureProfiles(int userId) { + public List<PictureProfile> getAvailablePictureProfiles( + boolean includeParams, UserHandle user) { + String[] packageNames = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + if (packageNames != null && packageNames.length == 1 && !packageNames[0].isEmpty()) { + return getPictureProfilesByPackage(packageNames[0], includeParams, user); + } return new ArrayList<>(); } @Override - public boolean setDefaultPictureProfile(String profileId, int userId) { + public boolean setDefaultPictureProfile(String profileId, UserHandle user) { // TODO: pass the profile ID to MediaQuality HAL when ready. return false; } @Override - public List<String> getPictureProfilePackageNames(int userId) { + public List<String> getPictureProfilePackageNames(UserHandle user) { String [] column = {BaseParameters.PARAMETER_PACKAGE}; List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column, null, null); @@ -174,25 +196,25 @@ public class MediaQualityService extends SystemService { } @Override - public List<PictureProfileHandle> getPictureProfileHandle(String[] id, int userId) { + public List<PictureProfileHandle> getPictureProfileHandle(String[] id, UserHandle user) { return new ArrayList<>(); } @Override - public List<SoundProfileHandle> getSoundProfileHandle(String[] id, int userId) { + public List<SoundProfileHandle> getSoundProfileHandle(String[] id, UserHandle user) { return new ArrayList<>(); } @Override - public SoundProfile createSoundProfile(SoundProfile sp, int userId) { + public SoundProfile createSoundProfile(SoundProfile sp, UserHandle user) { SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - ContentValues values = new ContentValues(); - values.put(BaseParameters.PARAMETER_TYPE, sp.getProfileType()); - values.put(BaseParameters.PARAMETER_NAME, sp.getName()); - values.put(BaseParameters.PARAMETER_PACKAGE, sp.getPackageName()); - values.put(BaseParameters.PARAMETER_INPUT_ID, sp.getInputId()); - values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(sp.getParameters())); + ContentValues values = getContentValues(null, + sp.getProfileType(), + sp.getName(), + sp.getPackageName(), + sp.getInputId(), + sp.getParameters()); // id is auto-generated by SQLite upon successful insertion of row Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, @@ -203,12 +225,22 @@ public class MediaQualityService extends SystemService { } @Override - public void updateSoundProfile(String id, SoundProfile pp, int userId) { - // TODO: implement + public void updateSoundProfile(String id, SoundProfile sp, UserHandle user) { + Long intId = mSoundProfileTempIdMap.inverse().get(id); + + ContentValues values = getContentValues(intId, + sp.getProfileType(), + sp.getName(), + sp.getPackageName(), + sp.getInputId(), + sp.getParameters()); + + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + db.replace(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values); } @Override - public void removeSoundProfile(String id, int userId) { + public void removeSoundProfile(String id, UserHandle user) { Long intId = mSoundProfileTempIdMap.inverse().get(id); if (intId != null) { SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); @@ -221,9 +253,10 @@ public class MediaQualityService extends SystemService { } @Override - public SoundProfile getSoundProfile(int type, String id, int userId) { + public SoundProfile getSoundProfile(int type, String id, boolean includeParams, + UserHandle user) { String selection = BaseParameters.PARAMETER_TYPE + " = ? AND " - + BaseParameters.PARAMETER_NAME + " = ?"; + + BaseParameters.PARAMETER_ID + " = ?"; String[] selectionArguments = {String.valueOf(type), id}; try ( @@ -247,7 +280,8 @@ public class MediaQualityService extends SystemService { } @Override - public List<SoundProfile> getSoundProfilesByPackage(String packageName, int userId) { + public List<SoundProfile> getSoundProfilesByPackage( + String packageName, boolean includeParams, UserHandle user) { String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; String[] selectionArguments = {packageName}; return getSoundProfilesBasedOnConditions(getAllMediaProfileColumns(), selection, @@ -255,18 +289,24 @@ public class MediaQualityService extends SystemService { } @Override - public List<SoundProfile> getAvailableSoundProfiles(int userId) { + public List<SoundProfile> getAvailableSoundProfiles( + boolean includeParams, UserHandle user) { + String[] packageNames = mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid()); + if (packageNames != null && packageNames.length == 1 && !packageNames[0].isEmpty()) { + return getSoundProfilesByPackage(packageNames[0], includeParams, user); + } return new ArrayList<>(); } @Override - public boolean setDefaultSoundProfile(String profileId, int userId) { + public boolean setDefaultSoundProfile(String profileId, UserHandle user) { // TODO: pass the profile ID to MediaQuality HAL when ready. return false; } @Override - public List<String> getSoundProfilePackageNames(int userId) { + public List<String> getSoundProfilePackageNames(UserHandle user) { String [] column = {BaseParameters.PARAMETER_NAME}; List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column, null, null); @@ -278,11 +318,16 @@ public class MediaQualityService extends SystemService { private void populateTempIdMap(BiMap<Long, String> map, Long id) { if (id != null && map.get(id) == null) { - String uuid = UUID.randomUUID().toString(); - while (map.inverse().containsKey(uuid)) { + String uuid; + int attempts = 0; + while (attempts < MAX_UUID_GENERATION_ATTEMPTS) { uuid = UUID.randomUUID().toString(); + if (!map.inverse().containsKey(uuid)) { + map.put(id, uuid); + return; + } + attempts++; } - map.put(id, uuid); } } @@ -309,7 +354,7 @@ public class MediaQualityService extends SystemService { return json.toString(); } - private PersistableBundle jsonToBundle(String jsonString) { + private PersistableBundle jsonToPersistableBundle(String jsonString) { PersistableBundle bundle = new PersistableBundle(); if (jsonString != null) { JSONObject jsonObject = null; @@ -340,6 +385,30 @@ public class MediaQualityService extends SystemService { return bundle; } + private ContentValues getContentValues(Long dbId, Integer profileType, String name, + String packageName, String inputId, PersistableBundle params) { + ContentValues values = new ContentValues(); + if (dbId != null) { + values.put(BaseParameters.PARAMETER_ID, dbId); + } + if (profileType != null) { + values.put(BaseParameters.PARAMETER_TYPE, profileType); + } + if (name != null) { + values.put(BaseParameters.PARAMETER_NAME, name); + } + if (packageName != null) { + values.put(BaseParameters.PARAMETER_PACKAGE, packageName); + } + if (inputId != null) { + values.put(BaseParameters.PARAMETER_INPUT_ID, inputId); + } + if (params != null) { + values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(params)); + } + return values; + } + private String[] getAllMediaProfileColumns() { return new String[]{ BaseParameters.PARAMETER_ID, @@ -358,7 +427,7 @@ public class MediaQualityService extends SystemService { getName(cursor), getInputId(cursor), getPackageName(cursor), - jsonToBundle(getSettingsString(cursor)), + jsonToPersistableBundle(getSettingsString(cursor)), PictureProfileHandle.NONE ); } @@ -370,7 +439,7 @@ public class MediaQualityService extends SystemService { getName(cursor), getInputId(cursor), getPackageName(cursor), - jsonToBundle(getSettingsString(cursor)), + jsonToPersistableBundle(getSettingsString(cursor)), SoundProfileHandle.NONE ); } @@ -456,70 +525,71 @@ public class MediaQualityService extends SystemService { } @Override - public void setAmbientBacklightSettings(AmbientBacklightSettings settings, int userId) { + public void setAmbientBacklightSettings( + AmbientBacklightSettings settings, UserHandle user) { } @Override - public void setAmbientBacklightEnabled(boolean enabled, int userId) { + public void setAmbientBacklightEnabled(boolean enabled, UserHandle user) { } @Override - public List<ParamCapability> getParamCapabilities(List<String> names, int userId) { + public List<ParamCapability> getParamCapabilities(List<String> names, UserHandle user) { return new ArrayList<>(); } @Override - public List<String> getPictureProfileAllowList(int userId) { + public List<String> getPictureProfileAllowList(UserHandle user) { return new ArrayList<>(); } @Override - public void setPictureProfileAllowList(List<String> packages, int userId) { + public void setPictureProfileAllowList(List<String> packages, UserHandle user) { } @Override - public List<String> getSoundProfileAllowList(int userId) { + public List<String> getSoundProfileAllowList(UserHandle user) { return new ArrayList<>(); } @Override - public void setSoundProfileAllowList(List<String> packages, int userId) { + public void setSoundProfileAllowList(List<String> packages, UserHandle user) { } @Override - public boolean isSupported(int userId) { + public boolean isSupported(UserHandle user) { return false; } @Override - public void setAutoPictureQualityEnabled(boolean enabled, int userId) { + public void setAutoPictureQualityEnabled(boolean enabled, UserHandle user) { } @Override - public boolean isAutoPictureQualityEnabled(int userId) { + public boolean isAutoPictureQualityEnabled(UserHandle user) { return false; } @Override - public void setSuperResolutionEnabled(boolean enabled, int userId) { + public void setSuperResolutionEnabled(boolean enabled, UserHandle user) { } @Override - public boolean isSuperResolutionEnabled(int userId) { + public boolean isSuperResolutionEnabled(UserHandle user) { return false; } @Override - public void setAutoSoundQualityEnabled(boolean enabled, int userId) { + public void setAutoSoundQualityEnabled(boolean enabled, UserHandle user) { } @Override - public boolean isAutoSoundQualityEnabled(int userId) { + public boolean isAutoSoundQualityEnabled(UserHandle user) { return false; } @Override - public boolean isAmbientBacklightEnabled(int userId) { + public boolean isAmbientBacklightEnabled(UserHandle user) { return false; } } diff --git a/services/core/java/com/android/server/media/quality/OWNERS b/services/core/java/com/android/server/media/quality/OWNERS index e455846dd75d..7171aa4ce9b6 100644 --- a/services/core/java/com/android/server/media/quality/OWNERS +++ b/services/core/java/com/android/server/media/quality/OWNERS @@ -1,2 +1,3 @@ shubang@google.com -haofanw@google.com
\ No newline at end of file +haofanw@google.com +pkandhalu@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 15af36ba66af..39eea740a902 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2594,6 +2594,7 @@ public class NotificationManagerService extends SystemService { intent.setPackage(pkg); intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id); intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); getContext().sendBroadcastAsUser(intent, UserHandle.of(userId)); }); } diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index c09077e349fd..f17ac5c92889 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -21,6 +21,7 @@ import android.content.Context; import android.os.Handler; import android.os.Message; import android.os.SystemClock; +import android.service.notification.RateEstimator; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index dc173b124884..95aff5652bb6 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -112,9 +112,10 @@ import android.util.SparseArray; import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; +import androidx.annotation.VisibleForTesting; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.FrameworkStatsLog; @@ -279,6 +280,11 @@ public class ZenModeHelper { mCallbacks.remove(callback); } + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + public List<Callback> getCallbacks() { + return mCallbacks; + } + public void initZenMode() { if (DEBUG) Log.d(TAG, "initZenMode"); synchronized (mConfigLock) { diff --git a/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java index 8ec716077f46..871d12ee6394 100644 --- a/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java +++ b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java @@ -20,116 +20,100 @@ import static android.Manifest.permission.DYNAMIC_INSTRUMENTATION; import static android.content.Context.DYNAMIC_INSTRUMENTATION_SERVICE; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.PermissionManuallyEnforced; +import android.annotation.RequiresPermission; +import android.app.ActivityManagerInternal; import android.content.Context; +import android.os.RemoteException; import android.os.instrumentation.ExecutableMethodFileOffsets; import android.os.instrumentation.IDynamicInstrumentationManager; +import android.os.instrumentation.IOffsetCallback; import android.os.instrumentation.MethodDescriptor; +import android.os.instrumentation.MethodDescriptorParser; import android.os.instrumentation.TargetProcess; -import com.android.internal.annotations.VisibleForTesting; + +import com.android.server.LocalServices; import com.android.server.SystemService; import dalvik.system.VMDebug; import java.lang.reflect.Method; +import java.util.NoSuchElementException; +import java.util.Objects; + /** * System private implementation of the {@link IDynamicInstrumentationManager interface}. */ public class DynamicInstrumentationManagerService extends SystemService { + + private ActivityManagerInternal mAmInternal; + public DynamicInstrumentationManagerService(@NonNull Context context) { super(context); } @Override public void onStart() { + mAmInternal = LocalServices.getService(ActivityManagerInternal.class); publishBinderService(DYNAMIC_INSTRUMENTATION_SERVICE, new BinderService()); } private final class BinderService extends IDynamicInstrumentationManager.Stub { @Override @PermissionManuallyEnforced - public @Nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets( - @NonNull TargetProcess targetProcess, @NonNull MethodDescriptor methodDescriptor) { + @RequiresPermission(value = android.Manifest.permission.DYNAMIC_INSTRUMENTATION) + public void getExecutableMethodFileOffsets( + @NonNull TargetProcess targetProcess, @NonNull MethodDescriptor methodDescriptor, + @NonNull IOffsetCallback callback) { if (!com.android.art.flags.Flags.executableMethodFileOffsets()) { throw new UnsupportedOperationException(); } getContext().enforceCallingOrSelfPermission( DYNAMIC_INSTRUMENTATION, "Caller must have DYNAMIC_INSTRUMENTATION permission"); + Objects.requireNonNull(targetProcess.processName); - if (targetProcess.processName == null - || !targetProcess.processName.equals("system_server")) { - throw new UnsupportedOperationException( - "system_server is the only supported target process"); + if (!targetProcess.processName.equals("system_server")) { + try { + mAmInternal.getExecutableMethodFileOffsets(targetProcess.processName, + targetProcess.pid, targetProcess.uid, methodDescriptor, + new IOffsetCallback.Stub() { + @Override + public void onResult(ExecutableMethodFileOffsets result) { + try { + callback.onResult(result); + } catch (RemoteException e) { + /* ignore */ + } + } + }); + return; + } catch (NoSuchElementException e) { + throw new IllegalArgumentException( + "The specified app process cannot be found." , e); + } } - Method method = parseMethodDescriptor( + Method method = MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), methodDescriptor); VMDebug.ExecutableMethodFileOffsets location = VMDebug.getExecutableMethodFileOffsets(method); - if (location == null) { - return null; - } - - ExecutableMethodFileOffsets ret = new ExecutableMethodFileOffsets(); - ret.containerPath = location.getContainerPath(); - ret.containerOffset = location.getContainerOffset(); - ret.methodOffset = location.getMethodOffset(); - return ret; - } - } - - @VisibleForTesting - static Method parseMethodDescriptor(ClassLoader classLoader, - @NonNull MethodDescriptor descriptor) { - try { - Class<?> javaClass = classLoader.loadClass(descriptor.fullyQualifiedClassName); - Class<?>[] parameters = new Class[descriptor.fullyQualifiedParameters.length]; - for (int i = 0; i < descriptor.fullyQualifiedParameters.length; i++) { - String typeName = descriptor.fullyQualifiedParameters[i]; - boolean isArrayType = typeName.endsWith("[]"); - if (isArrayType) { - typeName = typeName.substring(0, typeName.length() - 2); + try { + if (location == null) { + callback.onResult(null); + return; } - switch (typeName) { - case "boolean": - parameters[i] = isArrayType ? boolean.class.arrayType() : boolean.class; - break; - case "byte": - parameters[i] = isArrayType ? byte.class.arrayType() : byte.class; - break; - case "char": - parameters[i] = isArrayType ? char.class.arrayType() : char.class; - break; - case "short": - parameters[i] = isArrayType ? short.class.arrayType() : short.class; - break; - case "int": - parameters[i] = isArrayType ? int.class.arrayType() : int.class; - break; - case "long": - parameters[i] = isArrayType ? long.class.arrayType() : long.class; - break; - case "float": - parameters[i] = isArrayType ? float.class.arrayType() : float.class; - break; - case "double": - parameters[i] = isArrayType ? double.class.arrayType() : double.class; - break; - default: - parameters[i] = isArrayType ? classLoader.loadClass(typeName).arrayType() - : classLoader.loadClass(typeName); - } - } - return javaClass.getDeclaredMethod(descriptor.methodName, parameters); - } catch (ClassNotFoundException | NoSuchMethodException e) { - throw new IllegalArgumentException( - "The specified method cannot be found. Is this descriptor valid? " - + descriptor, e); + ExecutableMethodFileOffsets ret = new ExecutableMethodFileOffsets(); + ret.containerPath = location.getContainerPath(); + ret.containerOffset = location.getContainerOffset(); + ret.methodOffset = location.getMethodOffset(); + callback.onResult(ret); + } catch (RemoteException e) { + throw new RuntimeException("Failed to invoke result callback", e); + } } } } diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java index 6d54be84d5e5..67e10953ac91 100644 --- a/services/core/java/com/android/server/pm/BroadcastHelper.java +++ b/services/core/java/com/android/server/pm/BroadcastHelper.java @@ -53,6 +53,7 @@ import android.os.Handler; import android.os.PowerExemptionManager; import android.os.Process; import android.os.RemoteException; +import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; @@ -78,6 +79,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 +218,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 +238,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 */); } @@ -357,9 +359,14 @@ public final class BroadcastHelper { @Nullable int[] instantUserIds, @Nullable SparseArray<int[]> broadcastAllowList, @NonNull AndroidPackage pkg, - @NonNull String[] sharedUidPackages) { + @NonNull String[] sharedUidPackages, + @NonNull String reasonForTrace) { final boolean isForWholeApp = componentNames.contains(packageName); if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) { + tracePackageChangedBroadcastEvent( + android.content.pm.Flags.reduceBroadcastsForComponentStateChanges(), + reasonForTrace, "all" /* targetName */, "whole" /* targetComponent */, + componentNames.size()); sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, null /* targetPackageName */, null /* requiredPermissions */); @@ -381,6 +388,9 @@ public final class BroadcastHelper { // First, send the PACKAGE_CHANGED broadcast to the system. if (!TextUtils.equals(packageName, "android")) { + tracePackageChangedBroadcastEvent(true /* applyFlag */, reasonForTrace, + "system" /* targetName */, "notExported" /* targetComponent */, + notExportedComponentNames.size()); sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, notExportedComponentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, "android" /* targetPackageName */, @@ -389,6 +399,9 @@ public final class BroadcastHelper { } // Second, send the PACKAGE_CHANGED broadcast to the application itself. + tracePackageChangedBroadcastEvent(true /* applyFlag */, reasonForTrace, + "applicationItself" /* targetName */, "notExported" /* targetComponent */, + notExportedComponentNames.size()); sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, notExportedComponentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, packageName /* targetPackageName */, @@ -400,6 +413,9 @@ public final class BroadcastHelper { if (TextUtils.equals(packageName, sharedPackage)) { continue; } + tracePackageChangedBroadcastEvent(true /* applyFlag */, reasonForTrace, + "sharedUidPackages" /* targetName */, "notExported" /* targetComponent */, + notExportedComponentNames.size()); sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, notExportedComponentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, sharedPackage /* targetPackageName */, @@ -409,6 +425,9 @@ public final class BroadcastHelper { } if (!exportedComponentNames.isEmpty()) { + tracePackageChangedBroadcastEvent(true /* applyFlag */, reasonForTrace, + "all" /* targetName */, "exported" /* targetComponent */, + exportedComponentNames.size()); sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, exportedComponentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, null /* targetPackageName */, @@ -544,7 +563,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 +586,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 +627,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 +752,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); @@ -749,7 +769,8 @@ public final class BroadcastHelper { sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), dontKillApp, new ArrayList<>(Collections.singletonList(pkg.getPackageName())), - pkg.getUid(), null); + pkg.getUid(), null /* reason */, + "static_shared_library_changed" /* reasonForTrace */); } } } @@ -860,8 +881,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 +894,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)) { @@ -939,7 +961,8 @@ public final class BroadcastHelper { boolean dontKillApp, @NonNull ArrayList<String> componentNames, int packageUid, - @NonNull String reason) { + @NonNull String reason, + @NonNull String reasonForTrace) { PackageStateInternal setting = snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID); if (setting == null || setting.getPkg() == null) { @@ -952,10 +975,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, reasonForTrace)); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } @@ -1120,7 +1145,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 +1163,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 +1173,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 +1188,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 +1218,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 +1234,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 +1250,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); } @@ -1247,4 +1273,22 @@ public final class BroadcastHelper { mPackageMonitorCallbackHelper.notifyResourcesChanged(mediaStatus, replacing, pkgNames, uids, mHandler); } + + private static void tracePackageChangedBroadcastEvent(boolean applyFlag, String reasonForTrace, + String targetName, String targetComponent, int componentSize) { + + if (!Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) { + return; + } + + final StringBuilder builder = new StringBuilder(); + builder.append("broadcastPackageChanged; "); + builder.append("af="); builder.append(applyFlag); + builder.append(",rft="); builder.append(reasonForTrace); + builder.append(",tn="); builder.append(targetName); + builder.append(",tc="); builder.append(targetComponent); + builder.append(",cs="); builder.append(componentSize); + + Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, builder.toString()); + } } 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/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java index c0ddebeb9868..837adf004df7 100644 --- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java +++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java @@ -78,24 +78,22 @@ public class InstallDependencyHelper { mPackageInstallerService = packageInstallerService; } - void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId, - Handler handler, OutcomeReceiver<Void, PackageManagerException> origCallback) { + void resolveLibraryDependenciesIfNeeded(List<SharedLibraryInfo> missingLibraries, + PackageLite pkg, Computer snapshot, int userId, Handler handler, + OutcomeReceiver<Void, PackageManagerException> origCallback) { CallOnceProxy callback = new CallOnceProxy(handler, origCallback); try { - resolveLibraryDependenciesIfNeededInternal(pkg, snapshot, userId, handler, callback); - } catch (PackageManagerException e) { - callback.onError(e); + resolveLibraryDependenciesIfNeededInternal( + missingLibraries, pkg, snapshot, userId, handler, callback); } catch (Exception e) { onError(callback, e.getMessage()); } } - private void resolveLibraryDependenciesIfNeededInternal(PackageLite pkg, Computer snapshot, - int userId, Handler handler, CallOnceProxy callback) throws PackageManagerException { - final List<SharedLibraryInfo> missing = - mSharedLibraries.collectMissingSharedLibraryInfos(pkg); - + private void resolveLibraryDependenciesIfNeededInternal(List<SharedLibraryInfo> missing, + PackageLite pkg, Computer snapshot, int userId, Handler handler, + CallOnceProxy callback) { if (missing.isEmpty()) { if (DEBUG) { Slog.d(TAG, "No missing dependency for " + pkg.getPackageName()); @@ -129,6 +127,11 @@ public class InstallDependencyHelper { } } + List<SharedLibraryInfo> getMissingSharedLibraries(PackageLite pkg) + throws PackageManagerException { + return mSharedLibraries.collectMissingSharedLibraryInfos(pkg); + } + void notifySessionComplete(int sessionId) { if (DEBUG) { Slog.d(TAG, "Session complete for " + sessionId); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 69c6ce8ea0cd..b48b39c2edd5 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -2983,7 +2983,7 @@ final class InstallPackageHelper { } } - public void sendPendingBroadcasts() { + public void sendPendingBroadcasts(String reasonForTrace) { String[] packages; ArrayList<String>[] components; int numBroadcasts = 0, numUsers; @@ -3027,7 +3027,8 @@ final class InstallPackageHelper { // Send broadcasts for (int i = 0; i < numBroadcasts; i++) { mBroadcastHelper.sendPackageChangedBroadcast(snapshot, packages[i], - true /* dontKillApp */, components[i], uids[i], null /* reason */); + true /* dontKillApp */, components[i], uids[i], null /* reason */, + reasonForTrace); } } @@ -3084,7 +3085,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/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index b0fe3a97af6e..c96c160deb0f 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -170,6 +170,8 @@ final class InstallRequest { private final boolean mHasAppMetadataFileFromInstaller; private boolean mKeepArtProfile = false; + private final boolean mDependencyInstallerEnabled; + private final int mMissingSharedLibraryCount; // New install InstallRequest(InstallingSession params) { @@ -190,6 +192,8 @@ final class InstallRequest { mRequireUserAction = params.mRequireUserAction; mPreVerifiedDomains = params.mPreVerifiedDomains; mHasAppMetadataFileFromInstaller = params.mHasAppMetadataFile; + mDependencyInstallerEnabled = params.mDependencyInstallerEnabled; + mMissingSharedLibraryCount = params.mMissingSharedLibraryCount; } // Install existing package as user @@ -209,6 +213,8 @@ final class InstallRequest { mInstallerUidForInstallExisting = installerUid; mSystem = isSystem; mHasAppMetadataFileFromInstaller = false; + mDependencyInstallerEnabled = false; + mMissingSharedLibraryCount = 0; } // addForInit @@ -231,6 +237,8 @@ final class InstallRequest { mRequireUserAction = USER_ACTION_UNSPECIFIED; mDisabledPs = disabledPs; mHasAppMetadataFileFromInstaller = false; + mDependencyInstallerEnabled = false; + mMissingSharedLibraryCount = 0; } @Nullable @@ -1069,4 +1077,12 @@ final class InstallRequest { boolean isKeepArtProfile() { return mKeepArtProfile; } + + int getMissingSharedLibraryCount() { + return mMissingSharedLibraryCount; + } + + boolean isDependencyInstallerEnabled() { + return mDependencyInstallerEnabled; + } } diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java index ccc117566989..6a2bf83ba368 100644 --- a/services/core/java/com/android/server/pm/InstallingSession.java +++ b/services/core/java/com/android/server/pm/InstallingSession.java @@ -103,6 +103,8 @@ class InstallingSession { final DomainSet mPreVerifiedDomains; final boolean mHasAppMetadataFile; @Nullable final String mDexoptCompilerFilter; + final boolean mDependencyInstallerEnabled; + final int mMissingSharedLibraryCount; // For move install InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer, @@ -138,13 +140,16 @@ class InstallingSession { mPreVerifiedDomains = null; mHasAppMetadataFile = false; mDexoptCompilerFilter = null; + mDependencyInstallerEnabled = false; + mMissingSharedLibraryCount = 0; } InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams, InstallSource installSource, UserHandle user, SigningDetails signingDetails, int installerUid, PackageLite packageLite, DomainSet preVerifiedDomains, PackageManagerService pm, - boolean hasAppMetadatafile) { + boolean hasAppMetadatafile, boolean dependencyInstallerEnabled, + int missingSharedLibraryCount) { mPm = pm; mUser = user; mOriginInfo = OriginInfo.fromStagedFile(stagedDir); @@ -175,6 +180,8 @@ class InstallingSession { mPreVerifiedDomains = preVerifiedDomains; mHasAppMetadataFile = hasAppMetadatafile; mDexoptCompilerFilter = sessionParams.dexoptCompilerFilter; + mDependencyInstallerEnabled = dependencyInstallerEnabled; + mMissingSharedLibraryCount = missingSharedLibraryCount; } @Override diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index 4ea405441030..0a067048be42 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -76,7 +76,7 @@ final class PackageHandler extends Handler { void doHandleMessage(Message msg) { switch (msg.what) { case SEND_PENDING_BROADCAST: { - mPm.sendPendingBroadcasts(); + mPm.sendPendingBroadcasts((String) msg.obj); break; } case POST_INSTALL: { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 891d66a5d238..c6760431116e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -31,6 +31,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STOR import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE; +import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT; import static android.content.pm.PackageManager.INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE; import static android.content.pm.PackageManager.INSTALL_FAILED_SESSION_INVALID; @@ -109,6 +110,7 @@ import android.content.pm.PackageInstaller.UserActionReason; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManagerInternal; +import android.content.pm.SharedLibraryInfo; import android.content.pm.SigningDetails; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.parsing.ApkLite; @@ -540,6 +542,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private DomainSet mPreVerifiedDomains; + private AtomicBoolean mDependencyInstallerEnabled = new AtomicBoolean(); + private AtomicInteger mMissingSharedLibraryCount = new AtomicInteger(); + static class FileEntry { private final int mIndex; private final InstallationFile mFile; @@ -3232,6 +3237,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (Flags.sdkDependencyInstaller() && params.isAutoInstallDependenciesEnabled && !isMultiPackage()) { + mDependencyInstallerEnabled.set(true); resolveLibraryDependenciesIfNeeded(); } else { install(); @@ -3241,8 +3247,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void resolveLibraryDependenciesIfNeeded() { synchronized (mLock) { - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(mPackageLite, - mPm.snapshotComputer(), userId, mHandler, + List<SharedLibraryInfo> missingLibraries = new ArrayList<>(); + try { + missingLibraries = mInstallDependencyHelper.getMissingSharedLibraries(mPackageLite); + } catch (PackageManagerException e) { + handleDependencyResolutionFailure(e); + } catch (Exception e) { + handleDependencyResolutionFailure( + new PackageManagerException( + INSTALL_FAILED_MISSING_SHARED_LIBRARY, e.getMessage())); + } + + mMissingSharedLibraryCount.set(missingLibraries.size()); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(missingLibraries, + mPackageLite, mPm.snapshotComputer(), userId, mHandler, new OutcomeReceiver<>() { @Override @@ -3252,14 +3270,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void onError(@NonNull PackageManagerException e) { - final String completeMsg = ExceptionUtils.getCompleteMessage(e); - setSessionFailed(e.error, completeMsg); - onSessionDependencyResolveFailure(e.error, completeMsg); + handleDependencyResolutionFailure(e); } }); } } + private void handleDependencyResolutionFailure(@NonNull PackageManagerException e) { + final String completeMsg = ExceptionUtils.getCompleteMessage(e); + setSessionFailed(e.error, completeMsg); + onSessionDependencyResolveFailure(e.error, completeMsg); + PackageMetrics.onDependencyInstallationFailure( + sessionId, getPackageName(), e.error, mInstallerUid, params, + mMissingSharedLibraryCount.get()); + } + /** * Stages this session for install and returns a * {@link InstallingSession} representing this new staged state. @@ -3327,7 +3352,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { return new InstallingSession(sessionId, stageDir, localObserver, params, mInstallSource, user, mSigningDetails, mInstallerUid, mPackageLite, mPreVerifiedDomains, mPm, - mHasAppMetadataFile); + mHasAppMetadataFile, mDependencyInstallerEnabled.get(), + mMissingSharedLibraryCount.get()); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 65bb701563a8..aadf11227d89 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3531,7 +3531,10 @@ public class PackageManagerService implements PackageSender, TestUtilityService mPendingBroadcasts.addComponents(userId, packageName, updatedComponents); if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { - mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(SEND_PENDING_BROADCAST, + "reset_component_state_changed" /* obj */), + BROADCAST_DELAY); } } @@ -3828,7 +3831,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService mPendingBroadcasts.addComponent(userId, componentPkgName, componentName.getClassName()); if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) { - mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY); + mHandler.sendMessageDelayed(mHandler.obtainMessage(SEND_PENDING_BROADCAST, + "component_label_icon_changed" /* obj */), BROADCAST_DELAY); } } @@ -4063,6 +4067,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; } } @@ -4085,7 +4091,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final long broadcastDelay = SystemClock.uptimeMillis() > mServiceStartWithDelay ? BROADCAST_DELAY : BROADCAST_DELAY_DURING_STARTUP; - mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, broadcastDelay); + mHandler.sendMessageDelayed(mHandler.obtainMessage(SEND_PENDING_BROADCAST, + "component_state_changed" /* obj */), broadcastDelay); } } } @@ -4103,7 +4110,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final int packageUid = UserHandle.getUid( userId, pkgSettings.get(packageName).getAppId()); mBroadcastHelper.sendPackageChangedBroadcast(newSnapshot, packageName, - false /* dontKillApp */, components, packageUid, null /* reason */); + false /* dontKillApp */, components, packageUid, null /* reason */, + "component_state_changed" /* reasonForTrace */); } } finally { Binder.restoreCallingIdentity(callingId); @@ -4331,7 +4339,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService true /* dontKillApp */, new ArrayList<>(Collections.singletonList(pkg.getPackageName())), pkg.getUid(), - Intent.ACTION_OVERLAY_CHANGED); + Intent.ACTION_OVERLAY_CHANGED, "overlay_changed" /* reasonForTrace */); } }, overlayFilter); @@ -6382,7 +6390,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService if (pkgUserState != null && pkgUserState.isInstalled()) { final int packageUid = UserHandle.getUid(userIds[i], appId); mBroadcastHelper.sendPackageChangedBroadcast(snapShot, packageName, - true /* dontKillApp */, components, packageUid, reason); + true /* dontKillApp */, components, packageUid, reason, + "mime_group_changed" /* reasonForTrace */); } } }); @@ -8177,8 +8186,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService mRemovePackageHelper.cleanUpForMoveInstall(volumeUuid, packageName, fromCodePath); } - void sendPendingBroadcasts() { - mInstallPackageHelper.sendPendingBroadcasts(); + void sendPendingBroadcasts(String reasonForTrace) { + mInstallPackageHelper.sendPendingBroadcasts(reasonForTrace); } void handlePackagePostInstall(@NonNull InstallRequest request, boolean launchedForRestore) { 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/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java index 0acadb129f2b..856d6a726da5 100644 --- a/services/core/java/com/android/server/pm/PackageMetrics.java +++ b/services/core/java/com/android/server/pm/PackageMetrics.java @@ -32,7 +32,9 @@ import android.app.admin.SecurityLog; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.DataLoaderType; import android.content.pm.Flags; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.parsing.ApkLiteParseUtils; @@ -173,7 +175,10 @@ final class PackageMetrics { mInstallRequest.isInstallInherit() /* is_inherit */, mInstallRequest.isInstallForUsers() /* is_installing_existing_as_user */, mInstallRequest.isInstallMove() /* is_move_install */, - false /* is_staged */ + false /* is_staged */, + mInstallRequest + .isDependencyInstallerEnabled() /* is_install_dependencies_enabled */, + mInstallRequest.getMissingSharedLibraryCount() /* missing_dependencies_count */ ); } @@ -323,7 +328,53 @@ final class PackageMetrics { verifyingSession.isInherit() /* is_inherit */, false /* is_installing_existing_as_user */, false /* is_move_install */, - verifyingSession.isStaged() /* is_staged */ + verifyingSession.isStaged() /* is_staged */, + false /* is_install_dependencies_enabled */, + 0 /* missing_dependencies_count */ + ); + } + + static void onDependencyInstallationFailure( + int sessionId, String packageName, int errorCode, int installerPackageUid, + PackageInstaller.SessionParams params, int missingDependenciesCount) { + if (params == null) { + return; + } + int dataLoaderType = DataLoaderType.NONE; + if (params.dataLoaderParams != null) { + dataLoaderType = params.dataLoaderParams.getType(); + } + + FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLATION_SESSION_REPORTED, + sessionId /* session_id */, + packageName /* package_name */, + INVALID_UID /* uid */, + null /* user_ids */, + null /* user_types */, + null /* original_user_ids */, + null /* original_user_types */, + errorCode /* public_return_code */, + 0 /* internal_error_code */, + 0 /* apks_size_bytes */, + 0 /* version_code */, + null /* install_steps */, + null /* step_duration_millis */, + 0 /* total_duration_millis */, + 0 /* install_flags */, + installerPackageUid /* installer_package_uid */, + INVALID_UID /* original_installer_package_uid */, + dataLoaderType /* data_loader_type */, + params.requireUserAction /* user_action_required_type */, + (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0 /* is_instant */, + false /* is_replace */, + false /* is_system */, + params.mode + == PackageInstaller.SessionParams.MODE_INHERIT_EXISTING /* is_inherit */, + false /* is_installing_existing_as_user */, + false /* is_move_install */, + params.isStaged /* is_staged */, + true /* is_install_dependencies_enabled */, + missingDependenciesCount /* missing_dependencies_count */ ); } 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/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING index 94b49e538621..1fda4782fc86 100644 --- a/services/core/java/com/android/server/pm/TEST_MAPPING +++ b/services/core/java/com/android/server/pm/TEST_MAPPING @@ -165,6 +165,22 @@ ] }, { + "name": "CtsPackageInstallerCUJUpdateOwnerShipTestCases", + "file_patterns": [ + "core/java/.*Install.*", + "services/core/.*Install.*", + "services/core/java/com/android/server/pm/.*" + ], + "options":[ + { + "exclude-annotation":"androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation":"org.junit.Ignore" + } + ] + }, + { "name": "CtsPackageInstallerCUJUpdateSelfTestCases", "file_patterns": [ "core/java/.*Install.*", 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/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java index 542ae8eb9207..dd60a155f2fb 100644 --- a/services/core/java/com/android/server/pm/VerifyingSession.java +++ b/services/core/java/com/android/server/pm/VerifyingSession.java @@ -16,11 +16,7 @@ package com.android.server.pm; -import static android.content.Intent.EXTRA_LONG_VERSION_CODE; -import static android.content.Intent.EXTRA_PACKAGE_NAME; -import static android.content.Intent.EXTRA_VERSION_CODE; import static android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING; -import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; import static android.content.pm.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4; @@ -40,9 +36,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.BroadcastOptions; -import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.DataLoaderType; @@ -68,7 +62,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.incremental.IncrementalManager; import android.provider.DeviceConfig; -import android.provider.Settings; import android.text.TextUtils; import android.util.Pair; import android.util.Slog; 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/EventLogTags.logtags b/services/core/java/com/android/server/policy/EventLogTags.logtags index 75633820d01f..a4b6472fbe62 100644 --- a/services/core/java/com/android/server/policy/EventLogTags.logtags +++ b/services/core/java/com/android/server/policy/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. option java_package com.android.server.policy diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 7c4d4253157e..f1a481155458 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4081,6 +4081,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS: case KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH: case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: + case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: case KeyGestureEvent.KEY_GESTURE_TYPE_HOME: case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS: case KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN: @@ -4164,6 +4165,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } return true; case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT: + case KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT: if (complete) { launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, deviceId, SystemClock.uptimeMillis(), diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 36bc0b93cd7c..ce8dc69e4b26 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -7093,7 +7093,11 @@ public final class PowerManagerService extends SystemService if ((flags & PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) { if (mFoldGracePeriodProvider.isEnabled()) { if (!powerGroup.hasWakeLockKeepingScreenOnLocked()) { + Slog.d(TAG, "Showing dismissible keyguard"); mNotifier.showDismissibleKeyguard(); + } else { + Slog.i(TAG, "There is a screen wake lock present: " + + "sleep request will be ignored"); } continue; // never actually goes to sleep for SOFT_SLEEP } else { diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 987a84994451..137ea0617f21 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -296,7 +296,11 @@ public final class HintManagerService extends SystemService { mPowerHalVersion = 0; mUsesFmq = false; if (mPowerHal != null) { - mSupportInfo = getSupportInfo(); + try { + mSupportInfo = getSupportInfo(); + } catch (RemoteException e) { + throw new IllegalStateException("Could not contact PowerHAL!", e); + } } mDefaultCpuHeadroomCalculationWindowMillis = new CpuHeadroomParamsInternal().calculationWindowMillis; @@ -314,7 +318,7 @@ public final class HintManagerService extends SystemService { } } - SupportInfo getSupportInfo() { + SupportInfo getSupportInfo() throws RemoteException { try { mPowerHalVersion = mPowerHal.getInterfaceVersion(); if (mPowerHalVersion >= 6) { @@ -325,9 +329,40 @@ public final class HintManagerService extends SystemService { } SupportInfo supportInfo = new SupportInfo(); + supportInfo.usesSessions = isHintSessionSupported(); + // Global boosts & modes aren't currently relevant for HMS clients + supportInfo.boosts = 0; + supportInfo.modes = 0; + supportInfo.sessionHints = 0; + supportInfo.sessionModes = 0; + supportInfo.sessionTags = 0; + supportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); supportInfo.headroom.isCpuSupported = false; supportInfo.headroom.isGpuSupported = false; + if (isHintSessionSupported()) { + if (mPowerHalVersion == 4) { + // Assume we support the V4 hints & modes unless specified + // otherwise; this is to avoid breaking backwards compat + // since we historically just assumed they were. + supportInfo.sessionHints = 31; // first 5 bits are ones + } + if (mPowerHalVersion == 5) { + // Assume we support the V5 hints & modes unless specified + // otherwise; this is to avoid breaking backwards compat + // since we historically just assumed they were. + + // Hal V5 has 8 modes, all of which it assumes are supported, + // so we represent that by having the first 8 bits set + supportInfo.sessionHints = 255; // first 8 bits are ones + // Hal V5 has 1 mode which it assumes is supported, so we + // represent that by having the first bit set + supportInfo.sessionModes = 1; + // Hal V5 has 5 tags, all of which it assumes are supported, + // so we represent that by having the first 5 bits set + supportInfo.sessionTags = 31; + } + } return supportInfo; } @@ -1228,7 +1263,7 @@ public final class HintManagerService extends SystemService { @SessionTag int tag, SessionCreationConfig creationConfig, SessionConfig config) { if (!isHintSessionSupported()) { - throw new UnsupportedOperationException("PowerHAL is not supported!"); + throw new UnsupportedOperationException("PowerHintSessions are not supported!"); } java.util.Objects.requireNonNull(token); @@ -1424,12 +1459,6 @@ public final class HintManagerService extends SystemService { removeChannelItem(callingTgid, callingUid); }; - @Override - public long getHintSessionPreferredRate() { - return mHintSessionPreferredRate; - } - - @Override public int getMaxGraphicsPipelineThreadsCount() { return MAX_GRAPHICS_PIPELINE_THREADS_COUNT; } @@ -1561,6 +1590,16 @@ public final class HintManagerService extends SystemService { mSessionManager = ISessionManager.Stub.asInterface(sessionManager); } + public IHintManager.HintManagerClientData + registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) { + IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData(); + out.preferredRateNanos = mHintSessionPreferredRate; + out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount(); + out.powerHalVersion = mPowerHalVersion; + out.supportInfo = mSupportInfo; + return out; + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { @@ -1568,7 +1607,7 @@ public final class HintManagerService extends SystemService { } pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate); pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT); - pw.println("HAL Support: " + isHintSessionSupported()); + pw.println("Hint Session Support: " + isHintSessionSupported()); pw.println("Active Sessions:"); synchronized (mLock) { for (int i = 0; i < mActiveSessions.size(); i++) { 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..1b864bbe479c 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 @@ -170,13 +170,15 @@ public class PowerStatsAggregator { } } } - if (endTimeMs != MonotonicClock.UNDEFINED) { - lastTime = endTimeMs; - } - if (lastTime > baseTime) { - mStats.setDuration(lastTime - baseTime); - mStats.finish(lastTime); - consumer.accept(mStats); + if (startedSession) { + if (endTimeMs != MonotonicClock.UNDEFINED) { + lastTime = endTimeMs; + } + if (lastTime > baseTime) { + mStats.setDuration(lastTime - baseTime); + mStats.finish(lastTime); + consumer.accept(mStats); + } } mStats.reset(); // to free up memory diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java index 0ea88e8523f0..687442b47fb3 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java +++ b/services/core/java/com/android/server/security/intrusiondetection/DataAggregator.java @@ -28,6 +28,7 @@ import com.android.server.ServiceThread; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; public class DataAggregator { private static final String TAG = "IntrusionDetection DataAggregator"; @@ -36,11 +37,10 @@ public class DataAggregator { private static final int MSG_DISABLE = 2; private static final int STORED_EVENTS_SIZE_LIMIT = 1024; - private static final IntrusionDetectionAdminReceiver ADMIN_RECEIVER = - new IntrusionDetectionAdminReceiver(); private final IntrusionDetectionService mIntrusionDetectionService; private final ArrayList<DataSource> mDataSources; + private final AtomicBoolean mIsLoggingInitialized = new AtomicBoolean(false); private Context mContext; private List<IntrusionDetectionEvent> mStoredEvents = new ArrayList<>(); @@ -59,30 +59,20 @@ public class DataAggregator { mHandler = new EventHandler(looper, this); } - /** - * Initialize DataSources - * @return Whether the initialization succeeds. - */ - public boolean initialize() { - SecurityLogSource securityLogSource = new SecurityLogSource(mContext, this); - mDataSources.add(securityLogSource); - - NetworkLogSource networkLogSource = new NetworkLogSource(mContext, this); - ADMIN_RECEIVER.setNetworkLogEventCallback(networkLogSource); - mDataSources.add(networkLogSource); - - for (DataSource ds : mDataSources) { - if (!ds.initialize()) { - return false; - } - } - return true; + /** Initialize DataSources */ + private void initialize() { + mDataSources.add(new SecurityLogSource(mContext, this)); + mDataSources.add(new NetworkLogSource(mContext, this)); } /** * Enable the data collection of all DataSources. */ public void enable() { + if (!mIsLoggingInitialized.get()) { + initialize(); + mIsLoggingInitialized.set(true); + } mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND, /* allowIo */ false); mHandlerThread.start(); @@ -111,9 +101,6 @@ public class DataAggregator { */ public void disable() { mHandler.obtainMessage(MSG_DISABLE).sendToTarget(); - for (DataSource ds : mDataSources) { - ds.disable(); - } } private void onNewSingleData(IntrusionDetectionEvent event) { diff --git a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java index 61fac46be82d..0bc448245b76 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/DataSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/DataSource.java @@ -18,11 +18,6 @@ package com.android.server.security.intrusiondetection; public interface DataSource { /** - * Initialize the data source. - */ - boolean initialize(); - - /** * Enable the data collection. */ void enable(); diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java deleted file mode 100644 index dba7374fe02a..000000000000 --- a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionAdminReceiver.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.security.intrusiondetection; - -import android.app.admin.DeviceAdminReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Slog; - -public class IntrusionDetectionAdminReceiver extends DeviceAdminReceiver { - private static final String TAG = "IntrusionDetectionAdminReceiver"; - - private static NetworkLogSource sNetworkLogSource; - - @Override - public void onNetworkLogsAvailable( - Context context, Intent intent, long batchToken, int networkLogsCount) { - if (sNetworkLogSource != null) { - sNetworkLogSource.onNetworkLogsAvailable(batchToken); - } else { - Slog.w(TAG, "Network log receiver is not initialized"); - } - } - - public void setNetworkLogEventCallback(NetworkLogSource networkLogSource) { - sNetworkLogSource = networkLogSource; - } -} diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java index 2ddbeab5c8d8..a16e66de09a9 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java +++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionEventTransportConnection.java @@ -50,7 +50,7 @@ public class IntrusionDetectionEventTransportConnection implements ServiceConnec private static final String PRODUCTION_BUILD = "user"; private static final String PROPERTY_BUILD_TYPE = "ro.build.type"; private static final String PROPERTY_INTRUSION_DETECTION_SERVICE_NAME = - "intrusiondetection_service_name"; + "debug.intrusiondetection_package_name"; private static final long FUTURE_TIMEOUT_MILLIS = 60 * 1000; // 1 min private static final String TAG = "IntrusionDetectionEventTransportConnection"; private final Context mContext; @@ -147,9 +147,9 @@ public class IntrusionDetectionEventTransportConnection implements ServiceConnec } private String getSystemPropertyValue(String propertyName) { - String comamandString = "getprop " + propertyName; + String commandString = "getprop " + propertyName; try { - Process process = Runtime.getRuntime().exec(comamandString); + Process process = Runtime.getRuntime().exec(commandString); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String propertyValue = reader.readLine(); @@ -175,6 +175,10 @@ public class IntrusionDetectionEventTransportConnection implements ServiceConnec mIntrusionDetectionEventTransportConfig = getSystemPropertyValue(PROPERTY_INTRUSION_DETECTION_SERVICE_NAME); } + Slog.d( + TAG, + "mIntrusionDetectionEventTransportConfig: " + + mIntrusionDetectionEventTransportConfig); if (TextUtils.isEmpty(mIntrusionDetectionEventTransportConfig)) { Slog.e(TAG, "Unable to find a valid config for the transport service"); diff --git a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java index 0287b415b9c2..8ff1c7f22ffb 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java +++ b/services/core/java/com/android/server/security/intrusiondetection/IntrusionDetectionService.java @@ -232,12 +232,10 @@ public class IntrusionDetectionService extends SystemService { return; } - // TODO: temporarily disable the following for the CTS IntrusionDetectionManagerTest. - // Enable it when the transport component is ready. - // if (!mIntrusionDetectionEventTransportConnection.initialize()) { - // callback.onFailure(ERROR_TRANSPORT_UNAVAILABLE); - // return; - // } + if (!mIntrusionDetectionEventTransportConnection.initialize()) { + callback.onFailure(ERROR_TRANSPORT_UNAVAILABLE); + return; + } mDataAggregator.enable(); mState = STATE_ENABLED; @@ -252,9 +250,7 @@ public class IntrusionDetectionService extends SystemService { return; } - // TODO: temporarily disable the following for the CTS IntrusionDetectionManagerTest. - // Enable it when the transport component is ready. - // mIntrusionDetectionEventTransportConnection.release(); + mIntrusionDetectionEventTransportConnection.release(); mDataAggregator.disable(); mState = STATE_DISABLED; notifyStateMonitors(); diff --git a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java index 1c93d3f9c6a1..083b1fd61c46 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/NetworkLogSource.java @@ -17,118 +17,131 @@ package com.android.server.security.intrusiondetection; import android.app.admin.ConnectEvent; -import android.app.admin.DevicePolicyManager; import android.app.admin.DnsEvent; -import android.app.admin.NetworkEvent; -import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManagerInternal; +import android.net.IIpConnectivityMetrics; +import android.net.INetdEventCallback; +import android.net.metrics.IpConnectivityLog; +import android.os.RemoteException; +import android.os.ServiceManager; import android.security.intrusiondetection.IntrusionDetectionEvent; import android.util.Slog; -import java.util.List; -import java.util.stream.Collectors; +import com.android.server.LocalServices; +import com.android.server.net.BaseNetdEventCallback; + +import java.util.concurrent.atomic.AtomicBoolean; public class NetworkLogSource implements DataSource { private static final String TAG = "IntrusionDetectionEvent NetworkLogSource"; + private final AtomicBoolean mIsNetworkLoggingEnabled = new AtomicBoolean(false); + private final PackageManagerInternal mPm; - private DevicePolicyManager mDpm; - private ComponentName mAdmin; private DataAggregator mDataAggregator; - public NetworkLogSource(Context context, DataAggregator dataAggregator) { + private IIpConnectivityMetrics mIpConnectivityMetrics; + private long mId; + + public NetworkLogSource(Context context, DataAggregator dataAggregator) + throws SecurityException { mDataAggregator = dataAggregator; - mDpm = context.getSystemService(DevicePolicyManager.class); - mAdmin = new ComponentName(context, IntrusionDetectionAdminReceiver.class); + mPm = LocalServices.getService(PackageManagerInternal.class); + mId = 0; + initIpConnectivityMetrics(); } - @Override - public boolean initialize() { - try { - if (!mDpm.isAdminActive(mAdmin)) { - Slog.e(TAG, "Admin " + mAdmin.flattenToString() + "is not active admin"); - return false; - } - } catch (SecurityException e) { - Slog.e(TAG, "Security exception in initialize: ", e); - return false; - } - return true; + private void initIpConnectivityMetrics() { + mIpConnectivityMetrics = + (IIpConnectivityMetrics) + IIpConnectivityMetrics.Stub.asInterface( + ServiceManager.getService(IpConnectivityLog.SERVICE_NAME)); } @Override public void enable() { - enableNetworkLog(); - } - - @Override - public void disable() { - disableNetworkLog(); - } - - private void enableNetworkLog() { - if (!isNetworkLogEnabled()) { - mDpm.setNetworkLoggingEnabled(mAdmin, true); + if (mIsNetworkLoggingEnabled.get()) { + Slog.w(TAG, "Network logging is already enabled"); + return; } - } - - private void disableNetworkLog() { - if (isNetworkLogEnabled()) { - mDpm.setNetworkLoggingEnabled(mAdmin, false); + try { + if (mIpConnectivityMetrics.addNetdEventCallback( + INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, mNetdEventCallback)) { + mIsNetworkLoggingEnabled.set(true); + } else { + Slog.e(TAG, "Failed to enable network logging; invalid callback"); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to enable network logging; ", e); } } - private boolean isNetworkLogEnabled() { - return mDpm.isNetworkLoggingEnabled(mAdmin); - } - - /** - * Retrieve network logs when onNetworkLogsAvailable callback is received. - * - * @param batchToken The token representing the current batch of network logs. - */ - public void onNetworkLogsAvailable(long batchToken) { - List<NetworkEvent> events; - try { - events = mDpm.retrieveNetworkLogs(mAdmin, batchToken); - } catch (SecurityException e) { - Slog.e( - TAG, - "Admin " - + mAdmin.flattenToString() - + "does not have permission to retrieve network logs", - e); + @Override + public void disable() { + if (!mIsNetworkLoggingEnabled.get()) { + Slog.w(TAG, "Network logging is already disabled"); return; } - if (events == null) { - if (!isNetworkLogEnabled()) { - Slog.w(TAG, "Network logging is disabled"); + try { + if (!mIpConnectivityMetrics.removeNetdEventCallback( + INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST)) { + + mIsNetworkLoggingEnabled.set(false); } else { - Slog.e(TAG, "Invalid batch token: " + batchToken); + Slog.e(TAG, "Failed to enable network logging; invalid callback"); } - return; + } catch (RemoteException e) { + Slog.e(TAG, "Failed to disable network logging; ", e); } - - List<IntrusionDetectionEvent> intrusionDetectionEvents = - events.stream() - .filter(event -> event != null) - .map(event -> toIntrusionDetectionEvent(event)) - .collect(Collectors.toList()); - mDataAggregator.addBatchData(intrusionDetectionEvents); } - private IntrusionDetectionEvent toIntrusionDetectionEvent(NetworkEvent event) { - if (event instanceof DnsEvent) { - DnsEvent dnsEvent = (DnsEvent) event; - return new IntrusionDetectionEvent(dnsEvent); - } else if (event instanceof ConnectEvent) { - ConnectEvent connectEvent = (ConnectEvent) event; - return new IntrusionDetectionEvent(connectEvent); + private void incrementEventID() { + if (mId == Long.MAX_VALUE) { + Slog.i(TAG, "Reached maximum id value; wrapping around."); + mId = 0; + } else { + mId++; } - throw new IllegalArgumentException( - "Invalid event type with ID: " - + event.getId() - + "from package: " - + event.getPackageName()); } + + private final INetdEventCallback mNetdEventCallback = + new BaseNetdEventCallback() { + @Override + public void onDnsEvent( + int netId, + int eventType, + int returnCode, + String hostname, + String[] ipAddresses, + int ipAddressesCount, + long timestamp, + int uid) { + if (!mIsNetworkLoggingEnabled.get()) { + return; + } + DnsEvent dnsEvent = + new DnsEvent( + hostname, + ipAddresses, + ipAddressesCount, + mPm.getNameForUid(uid), + timestamp); + dnsEvent.setId(mId); + incrementEventID(); + mDataAggregator.addSingleData(new IntrusionDetectionEvent(dnsEvent)); + } + + @Override + public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) { + if (!mIsNetworkLoggingEnabled.get()) { + return; + } + ConnectEvent connectEvent = + new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), timestamp); + connectEvent.setId(mId); + incrementEventID(); + mDataAggregator.addSingleData(new IntrusionDetectionEvent(connectEvent)); + } + }; } diff --git a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java index c5f736e383b2..5611905bf270 100644 --- a/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java +++ b/services/core/java/com/android/server/security/intrusiondetection/SecurityLogSource.java @@ -43,26 +43,9 @@ public class SecurityLogSource implements DataSource { mDataAggregator = dataAggregator; mDpm = context.getSystemService(DevicePolicyManager.class); mExecutor = Executors.newSingleThreadExecutor(); - } - - @Override - public boolean initialize() { - // Confirm caller is system and the device is managed. Otherwise logs will - // be redacted. - try { - if (!mDpm.isDeviceManaged()) { - Slog.e(TAG, "Caller does not have device owner permissions"); - return false; - } - } catch (SecurityException e) { - Slog.e(TAG, "Security exception in initialize: ", e); - return false; - } mEventCallback = new SecurityEventCallback(); - return true; } - @Override @RequiresPermission(permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void enable() { @@ -99,6 +82,10 @@ public class SecurityLogSource implements DataSource { @Override public void accept(List<SecurityEvent> events) { + if (events.size() == 0) { + Slog.w(TAG, "No events received; caller may not be authorized"); + return; + } List<IntrusionDetectionEvent> intrusionDetectionEvents = events.stream() .filter(event -> event != null) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 3467f947ece4..5989fc8465c6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3212,8 +3212,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * will be ignored. */ boolean isUniversalResizeable() { - final boolean isLargeScreen = mDisplayContent != null && mDisplayContent.getConfiguration() - .smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP + final boolean isLargeScreen = mDisplayContent != null && mDisplayContent.isLargeScreen() && mDisplayContent.getIgnoreOrientationRequest(); if (!canBeUniversalResizeable(info.applicationInfo, mWmService, isLargeScreen, true /* forActivity */)) { @@ -4585,6 +4584,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** + * Returns {@code true} if the requested orientation of this activity is the same as the + * resolved orientation of the from activity. + */ + private boolean isStartingOrientationCompatible(@NonNull ActivityRecord fromActivity) { + final int fromOrientation = fromActivity.getConfiguration().orientation; + final int requestedOrientation = getRequestedConfigurationOrientation(); + if (requestedOrientation == ORIENTATION_UNDEFINED) { + return fromOrientation == getConfiguration().orientation; + } + return fromOrientation == requestedOrientation; + } + private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) { final WindowState tStartingWindow = fromActivity.mStartingWindow; if (tStartingWindow != null && fromActivity.mStartingSurface != null) { @@ -4604,13 +4616,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Do not transfer if the orientation doesn't match, redraw starting window while it is // on top will cause flicker. - final int fromOrientation = fromActivity.getConfiguration().orientation; - final int requestedOrientation = getRequestedConfigurationOrientation(); - if (requestedOrientation == ORIENTATION_UNDEFINED) { - if (fromOrientation != getConfiguration().orientation) { - return false; - } - } else if (fromOrientation != requestedOrientation) { + if (!isStartingOrientationCompatible(fromActivity)) { return false; } @@ -4708,6 +4714,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } return true; } else if (fromActivity.mStartingData != null) { + if (fromActivity.mStartingData instanceof SnapshotStartingData + && !isStartingOrientationCompatible(fromActivity)) { + // Do not transfer because the snapshot will be distorted in different orientation. + return false; + } // The previous app was getting ready to show a // starting window, but hasn't yet done so. Steal it! ProtoLog.v(WM_DEBUG_STARTING_WINDOW, @@ -5408,10 +5419,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void setDeferHidingClient() { + if (Flags.removeDeferHidingClient()) { + return; + } mDeferHidingClient = true; } void clearDeferHidingClient() { + if (Flags.removeDeferHidingClient()) { + return; + } if (!mDeferHidingClient) return; mDeferHidingClient = false; if (!mVisibleRequested) { @@ -7141,9 +7158,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void setClientVisible(boolean clientVisible) { - // TODO(shell-transitions): Remove mDeferHidingClient once everything is shell-transitions. - // pip activities should just remain in clientVisible. - if (!clientVisible && mDeferHidingClient) return; + if (!Flags.removeDeferHidingClient()) { + // TODO(shell-transitions): Remove mDeferHidingClient once everything is + // shell-transitions. pip activities should just remain in clientVisible. + if (!clientVisible && mDeferHidingClient) return; + } super.setClientVisible(clientVisible); } diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index 1208b6ef396f..08ceb61e14a8 100644 --- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -142,6 +142,8 @@ public class ActivityServiceConnectionsHolder<T> { /** Used by {@link ActivityRecord#dump}. */ @Override public String toString() { - return String.valueOf(mConnections); + synchronized (mActivity) { + return String.valueOf(mConnections); + } } } 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/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0ebdaed1bc02..afa7ea136c77 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1555,7 +1555,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final ActivityRecord[] outActivity = new ActivityRecord[1]; - getActivityStartController().obtainStarter(intent, "dream") + final int res = getActivityStartController() + .obtainStarter(intent, "dream") .setCallingUid(callingUid) .setCallingPid(callingPid) .setCallingPackage(intent.getPackage()) @@ -1569,9 +1570,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { .execute(); final ActivityRecord started = outActivity[0]; - final IAppTask appTask = started == null ? null : - new AppTaskImpl(this, started.getTask().mTaskId, callingUid); - return appTask; + if (started == null || !ActivityManager.isStartResultSuccessful(res)) { + // start the dream activity failed. + return null; + } + return new AppTaskImpl(this, started.getTask().mTaskId, callingUid); } } diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index 93ccd74c6b23..6ccceb9cf564 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -243,6 +243,19 @@ final class ContentRecorder implements WindowContainerListener { } } + /** Called when the surface of display is changed to a different instance. */ + void resetRecordingDisplay(int displayId) { + if (!isCurrentlyRecording() + || mContentRecordingSession.getDisplayToRecord() != displayId) { + return; + } + ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, + "Content Recording: Display %d changed surface so stop recording", displayId); + mDisplayContent.mWmService.mTransactionFactory.get().remove(mRecordedSurface).apply(); + mRecordedSurface = null; + // Do not un-set the token, in case new surface is ready and recording should begin again. + } + /** * Pauses recording on this display content. Note the session does not need to be updated, * since recording can be resumed still. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 3189acbc2fbf..f8086615b7d1 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; @@ -438,6 +439,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ private boolean mSandboxDisplayApis = true; + /** Whether {@link #setIgnoreOrientationRequest} is called to override the default policy. */ + @VisibleForTesting + boolean mHasSetIgnoreOrientationRequest; + /** * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity} * but can be set from Settings or via shell command "adb shell wm density". @@ -1272,7 +1277,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override void migrateToNewSurfaceControl(Transaction t) { t.remove(mSurfaceControl); - + // Reset the recording displays which were mirroring this display. + for (int i = mRootWindowContainer.getChildCount() - 1; i >= 0; i--) { + final ContentRecorder recorder = mRootWindowContainer.getChildAt(i).mContentRecorder; + if (recorder != null) { + recorder.resetRecordingDisplay(mDisplayId); + } + } mLastSurfacePosition.set(0, 0); mLastDeltaRotation = Surface.ROTATION_0; @@ -1384,11 +1395,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(); @@ -6710,8 +6726,25 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return mDisplayPolicy.getSystemUiContext(); } + /** Returns {@code} true if the smallest screen width dp >= 600. */ + boolean isLargeScreen() { + return getConfiguration().smallestScreenWidthDp + >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP; + } + + @Override + boolean getIgnoreOrientationRequest() { + if (mHasSetIgnoreOrientationRequest + || !com.android.window.flags.Flags.universalResizableByDefault()) { + return super.getIgnoreOrientationRequest(); + } + // Large screen (sw >= 600dp) ignores orientation request by default. + return isLargeScreen() && !mWmService.isIgnoreOrientationRequestDisabled(); + } + @Override boolean setIgnoreOrientationRequest(boolean ignoreOrientationRequest) { + mHasSetIgnoreOrientationRequest = true; if (mSetIgnoreOrientationRequest == ignoreOrientationRequest) return false; final boolean rotationChanged = super.setIgnoreOrientationRequest(ignoreOrientationRequest); mWmService.mDisplayWindowSettings.setIgnoreOrientationRequest( diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index f6d05d08cb04..f0ba822c37c5 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -374,9 +374,9 @@ class DisplayWindowSettings { final DisplayInfo displayInfo = dc.getDisplayInfo(); final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo); - final boolean ignoreOrientationRequest = settings.mIgnoreOrientationRequest != null - ? settings.mIgnoreOrientationRequest : false; - dc.setIgnoreOrientationRequest(ignoreOrientationRequest); + if (settings.mIgnoreOrientationRequest != null) { + dc.setIgnoreOrientationRequest(settings.mIgnoreOrientationRequest); + } dc.getDisplayRotation().resetAllowAllRotations(); } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 4230cd868c03..cba606cf2b0c 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -324,7 +324,8 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { if (target != imeControlTarget) { // TODO(b/353463205): check if fromUser=false is correct here boolean imeVisible = target.isRequestedVisible(WindowInsets.Type.ime()); - ImeTracker.Token statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, + ImeTracker.Token statsToken = ImeTracker.forLogging().onStart( + imeVisible ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_SERVER, imeVisible ? SoftInputShowHideReason.SHOW_INPUT_TARGET_CHANGED : SoftInputShowHideReason.HIDE_INPUT_TARGET_CHANGED, diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 27f82d90fdac..7fdc2c67b5ce 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -40,7 +40,7 @@ import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS; -import static com.android.launcher3.Flags.enableRefactorTaskThumbnail; +import static com.android.launcher3.Flags.enableUseTopVisibleActivityForExcludeFromRecentTask; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; @@ -1529,7 +1529,7 @@ class RecentTasks { // The Recents is only supported on default display now, we should only keep the // most recent task of home display. boolean isMostRecentTask; - if (enableRefactorTaskThumbnail()) { + if (enableUseTopVisibleActivityForExcludeFromRecentTask()) { isMostRecentTask = task.getTopVisibleActivity() != null; } else { isMostRecentTask = taskIndex == 0; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 46312aff1fb6..b3b8c6eab25e 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -156,6 +156,7 @@ import com.android.server.policy.PermissionPolicyInternal; import com.android.server.policy.WindowManagerPolicy; import com.android.server.utils.Slogf; import com.android.server.wm.utils.RegionUtils; +import com.android.window.flags.Flags; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -262,6 +263,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> int mCurrentUser; /** Root task id of the front root task when user switched, indexed by userId. */ SparseIntArray mUserRootTaskInFront = new SparseIntArray(2); + SparseArray<IntArray> mUserVisibleRootTasks = new SparseArray<>(); /** * A list of tokens that cause the top activity to be put to sleep. @@ -1924,7 +1926,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // appropriate. removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED); - mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + final IntArray visibleRootTasks = new IntArray(); + forAllRootTasks(rootTask -> { + if (mCurrentUser == rootTask.mUserId && rootTask.isVisibleRequested()) { + visibleRootTasks.add(rootTask.getRootTaskId()); + } + }, /* traverseTopToBottom */ false); + mUserVisibleRootTasks.put(mCurrentUser, visibleRootTasks); + } else { + mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + } + mCurrentUser = userId; mTaskSupervisor.mStartingUsers.add(uss); @@ -1937,22 +1950,60 @@ class RootWindowContainer extends WindowContainer<DisplayContent> Slog.i(TAG, "Persisting top task because it belongs to an always-visible user"); // For a normal user-switch, we will restore the new user's task. But if the pre-switch // top task is an always-visible (Communal) one, keep it even after the switch. - mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + final IntArray rootTasks = mUserVisibleRootTasks.get(mCurrentUser); + rootTasks.add(focusRootTaskId); + mUserVisibleRootTasks.put(mCurrentUser, rootTasks); + } else { + mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + } + } final int restoreRootTaskId = mUserRootTaskInFront.get(userId); + final IntArray rootTaskIdsToRestore = mUserVisibleRootTasks.get(userId); + boolean homeInFront = false; + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + if (rootTaskIdsToRestore == null) { + // If there are no root tasks saved, try restore id 0 which should create and launch + // the home task. + handleRootTaskLaunchOnUserSwitch(/* restoreRootTaskId */INVALID_TASK_ID); + homeInFront = true; + } else { + for (int i = 0; i < rootTaskIdsToRestore.size(); i++) { + handleRootTaskLaunchOnUserSwitch(rootTaskIdsToRestore.get(i)); + } + // Check if the top task is type home + if (rootTaskIdsToRestore.size() > 0) { + final int topRootTaskId = rootTaskIdsToRestore.get( + rootTaskIdsToRestore.size() - 1); + homeInFront = isHomeTask(topRootTaskId); + } + } + } else { + handleRootTaskLaunchOnUserSwitch(restoreRootTaskId); + // Check if the top task is type home + homeInFront = isHomeTask(restoreRootTaskId); + } + return homeInFront; + } + + private boolean isHomeTask(int taskId) { + final Task rootTask = getRootTask(taskId); + return rootTask != null && rootTask.isActivityTypeHome(); + } + + private void handleRootTaskLaunchOnUserSwitch(int restoreRootTaskId) { Task rootTask = getRootTask(restoreRootTaskId); if (rootTask == null) { rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } - final boolean homeInFront = rootTask.isActivityTypeHome(); if (rootTask.isOnHomeDisplay()) { rootTask.moveToFront("switchUserOnHomeDisplay"); } else { // Root task was moved to another display while user was swapped out. resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea()); } - return homeInFront; } /** Returns whether the given user is to be always-visible (e.g. a communal profile). */ @@ -1963,7 +2014,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void removeUser(int userId) { - mUserRootTaskInFront.delete(userId); + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + mUserVisibleRootTasks.delete(userId); + } else { + mUserRootTaskInFront.delete(userId); + } } /** @@ -1976,7 +2031,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } - mUserRootTaskInFront.put(userId, rootTask.getRootTaskId()); + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + final IntArray rootTasks = mUserVisibleRootTasks.get(userId, new IntArray()); + rootTasks.add(rootTask.getRootTaskId()); + mUserVisibleRootTasks.put(userId, rootTasks); + } else { + mUserRootTaskInFront.put(userId, rootTask.getRootTaskId()); + } } } @@ -2124,7 +2185,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (!tf.isOrganizedTaskFragment()) { return; } - tf.resetAdjacentTaskFragment(); + tf.clearAdjacentTaskFragments(); tf.setCompanionTaskFragment(null /* companionTaskFragment */); tf.setAnimationParams(TaskFragmentAnimationParams.DEFAULT); if (tf.getTopNonFinishingActivity() != null) { 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/Task.java b/services/core/java/com/android/server/wm/Task.java index 4ed120631bd5..c8befb21fe13 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3864,6 +3864,9 @@ class Task extends TaskFragment { if (mLaunchAdjacentDisabled) { pw.println(prefix + "mLaunchAdjacentDisabled=true"); } + if (mReparentLeafTaskIfRelaunch) { + pw.println(prefix + "mReparentLeafTaskIfRelaunch=true"); + } } @Override @@ -4489,7 +4492,7 @@ class Task extends TaskFragment { } void onPictureInPictureParamsChanged() { - if (inPinnedWindowingMode()) { + if (inPinnedWindowingMode() || Flags.enableDesktopWindowingPip()) { dispatchTaskInfoChangedIfNeeded(true /* force */); } } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 2c71c1a1f4f3..c1a33c468cee 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -31,6 +31,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.Display.INVALID_DISPLAY; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK; import static com.android.server.wm.DisplayContent.alwaysCreateRootTask; @@ -918,6 +919,10 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { if (candidateTask.getParent() == null) { addChild(candidateTask, position); } else { + if (candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) { + ProtoLog.d(WM_DEBUG_TASKS, "Reparenting to display area on relaunch: " + + "rootTaskId=%d toTop=%b", candidateTask.mTaskId, onTop); + } candidateTask.reparent(this, onTop); } } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 51b8bd1f0091..9fb5bea132ef 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -94,6 +94,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.UserHandle; +import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -239,12 +240,20 @@ class TaskFragment extends WindowContainer<WindowContainer> { /** This task fragment will be removed when the cleanup of its children are done. */ private boolean mIsRemovalRequested; - /** The TaskFragment that is adjacent to this one. */ + /** @deprecated b/373709676 replace with {@link #mAdjacentTaskFragments} */ + @Deprecated @Nullable private TaskFragment mAdjacentTaskFragment; /** - * Unlike the {@link mAdjacentTaskFragment}, the companion TaskFragment is not always visually + * The TaskFragments that are adjacent to each other, including this TaskFragment. + * All TaskFragments in this set share the same set instance. + */ + @Nullable + private AdjacentSet mAdjacentTaskFragments; + + /** + * Unlike the {@link #mAdjacentTaskFragments}, the companion TaskFragment is not always visually * adjacent to this one, but this TaskFragment will be removed by the organizer if the * companion TaskFragment is removed. */ @@ -442,15 +451,24 @@ class TaskFragment extends WindowContainer<WindowContainer> { return service.mWindowOrganizerController.getTaskFragment(token); } - void setAdjacentTaskFragment(@Nullable TaskFragment taskFragment) { - if (mAdjacentTaskFragment == taskFragment) { - return; - } - resetAdjacentTaskFragment(); - if (taskFragment != null) { + /** @deprecated b/373709676 replace with {@link #setAdjacentTaskFragments}. */ + @Deprecated + void setAdjacentTaskFragment(@NonNull TaskFragment taskFragment) { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + if (mAdjacentTaskFragment == taskFragment) { + return; + } + resetAdjacentTaskFragment(); mAdjacentTaskFragment = taskFragment; taskFragment.setAdjacentTaskFragment(this); + return; } + + setAdjacentTaskFragments(new AdjacentSet(this, taskFragment)); + } + + void setAdjacentTaskFragments(@NonNull AdjacentSet adjacentTaskFragments) { + adjacentTaskFragments.setAsAdjacent(); } void setCompanionTaskFragment(@Nullable TaskFragment companionTaskFragment) { @@ -461,7 +479,14 @@ class TaskFragment extends WindowContainer<WindowContainer> { return mCompanionTaskFragment; } - void resetAdjacentTaskFragment() { + /** @deprecated b/373709676 replace with {@link #clearAdjacentTaskFragments()}. */ + @Deprecated + private void resetAdjacentTaskFragment() { + if (Flags.allowMultipleAdjacentTaskFragments()) { + throw new IllegalStateException("resetAdjacentTaskFragment shouldn't be called when" + + " allowMultipleAdjacentTaskFragments is enabled. Use either" + + " #clearAdjacentTaskFragments or #removeFromAdjacentTaskFragments"); + } // Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment. if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) { mAdjacentTaskFragment.mAdjacentTaskFragment = null; @@ -471,6 +496,57 @@ class TaskFragment extends WindowContainer<WindowContainer> { mDelayLastActivityRemoval = false; } + void clearAdjacentTaskFragments() { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + resetAdjacentTaskFragment(); + return; + } + + if (mAdjacentTaskFragments != null) { + mAdjacentTaskFragments.clear(); + } + } + + void removeFromAdjacentTaskFragments() { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + resetAdjacentTaskFragment(); + return; + } + + if (mAdjacentTaskFragments != null) { + mAdjacentTaskFragments.remove(this); + } + } + + // TODO(b/373709676): update usages. + /** @deprecated b/373709676 replace with {@link #getAdjacentTaskFragments()}. */ + @Deprecated + @Nullable + TaskFragment getAdjacentTaskFragment() { + return mAdjacentTaskFragment; + } + + @Nullable + AdjacentSet getAdjacentTaskFragments() { + return mAdjacentTaskFragments; + } + + boolean hasAdjacentTaskFragment() { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + return mAdjacentTaskFragment != null; + } + return mAdjacentTaskFragments != null; + } + + boolean isAdjacentTo(@NonNull TaskFragment other) { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + return mAdjacentTaskFragment == other; + } + return other != this + && mAdjacentTaskFragments != null + && mAdjacentTaskFragments.contains(other); + } + void setTaskFragmentOrganizer(@NonNull TaskFragmentOrganizerToken organizer, int uid, @NonNull String processName) { mTaskFragmentOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.asBinder()); @@ -566,10 +642,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { return isEmbedded() && mPinned; } - TaskFragment getAdjacentTaskFragment() { - return mAdjacentTaskFragment; - } - /** Returns the currently topmost resumed activity. */ @Nullable ActivityRecord getTopResumedActivity() { @@ -616,7 +688,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { mResumedActivity = r; final ActivityRecord topResumed = mTaskSupervisor.updateTopResumedActivityIfNeeded(reason); if (mResumedActivity != null && topResumed != null && topResumed.isEmbedded() - && topResumed.getTaskFragment().getAdjacentTaskFragment() == this) { + && topResumed.getTaskFragment().isAdjacentTo(this)) { // Explicitly updates the last resumed Activity if the resumed activity is // adjacent to the top-resumed embedded activity. mAtmService.setLastResumedActivityUncheckLocked(mResumedActivity, reason); @@ -2036,7 +2108,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { private boolean shouldReportOrientationUnspecified() { // Apps and their containers are not allowed to specify orientation from adjacent // TaskFragment. - return getAdjacentTaskFragment() != null && isVisibleRequested(); + return hasAdjacentTaskFragment() && isVisibleRequested(); } @Override @@ -3086,7 +3158,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { EventLogTags.writeWmTfRemoved(System.identityHashCode(this), getTaskId()); } mIsRemovalRequested = false; - resetAdjacentTaskFragment(); + removeFromAdjacentTaskFragments(); cleanUpEmbeddedTaskFragment(); final boolean shouldExecuteAppTransition = mClearedTaskFragmentForPip && isTaskVisibleRequested(); @@ -3267,9 +3339,16 @@ class TaskFragment extends WindowContainer<WindowContainer> { sb.append(" organizerProc="); sb.append(mTaskFragmentOrganizerProcessName); } - if (mAdjacentTaskFragment != null) { - sb.append(" adjacent="); - sb.append(mAdjacentTaskFragment); + if (Flags.allowMultipleAdjacentTaskFragments()) { + if (mAdjacentTaskFragments != null) { + sb.append(" adjacent="); + sb.append(mAdjacentTaskFragments); + } + } else { + if (mAdjacentTaskFragment != null) { + sb.append(" adjacent="); + sb.append(mAdjacentTaskFragment); + } } sb.append('}'); return sb.toString(); @@ -3385,4 +3464,94 @@ class TaskFragment extends WindowContainer<WindowContainer> { proto.end(token); } + + /** Set of {@link TaskFragment}s that are adjacent to each other. */ + static class AdjacentSet { + private final ArraySet<TaskFragment> mAdjacentSet; + + AdjacentSet(@NonNull TaskFragment... taskFragments) { + this(new ArraySet<>(taskFragments)); + } + + AdjacentSet(@NonNull ArraySet<TaskFragment> taskFragments) { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + throw new IllegalStateException("allowMultipleAdjacentTaskFragments must be" + + " enabled to set more than two TaskFragments adjacent to each other."); + } + if (taskFragments.size() < 2) { + throw new IllegalArgumentException("Adjacent TaskFragments must contain at least" + + " two TaskFragments, but only " + taskFragments.size() + + " were provided."); + } + mAdjacentSet = taskFragments; + } + + /** Updates each {@link TaskFragment} in the set to be adjacent to each other. */ + private void setAsAdjacent() { + if (mAdjacentSet.isEmpty() + || equals(mAdjacentSet.valueAt(0).mAdjacentTaskFragments)) { + // No need to update if any TaskFragment in the set has already been updated to the + // same set. + return; + } + for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { + final TaskFragment taskFragment = mAdjacentSet.valueAt(i); + taskFragment.removeFromAdjacentTaskFragments(); + taskFragment.mAdjacentTaskFragments = this; + } + } + + /** Removes the {@link TaskFragment} from the adjacent set. */ + private void remove(@NonNull TaskFragment taskFragment) { + taskFragment.mAdjacentTaskFragments = null; + taskFragment.mDelayLastActivityRemoval = false; + mAdjacentSet.remove(taskFragment); + if (mAdjacentSet.size() < 2) { + // To be considered as adjacent, there must be at least 2 TaskFragments in the set. + clear(); + } + } + + /** Clears the adjacent relationship. */ + private void clear() { + for (int i = mAdjacentSet.size() - 1; i >= 0; i--) { + final TaskFragment taskFragment = mAdjacentSet.valueAt(i); + // Clear all reference. + taskFragment.mAdjacentTaskFragments = null; + taskFragment.mDelayLastActivityRemoval = false; + } + mAdjacentSet.clear(); + } + + /** Whether the {@link TaskFragment} is in this adjacent set. */ + boolean contains(@NonNull TaskFragment taskFragment) { + return mAdjacentSet.contains(taskFragment); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) { + return true; + } + if (!(o instanceof AdjacentSet other)) { + return false; + } + return mAdjacentSet.equals(other.mAdjacentSet); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("AdjacentSet{"); + final int size = mAdjacentSet.size(); + for (int i = 0; i < size; i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(mAdjacentSet.valueAt(i)); + } + sb.append("}"); + return sb.toString(); + } + } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 1fc609b7d03a..bcd12f253299 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1870,7 +1870,13 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { final DisplayArea<?> da = wc.asDisplayArea(); if (da == null) continue; if (da.isVisibleRequested()) { - mController.mValidateDisplayVis.remove(da); + final int inValidateList = mController.mValidateDisplayVis.indexOf(da); + if (inValidateList >= 0 + // The display-area is visible, but if we only detect a non-visibility + // change, then we shouldn't remove the validator. + && !mChanges.get(da).mVisible) { + mController.mValidateDisplayVis.remove(inValidateList); + } } else { // In case something accidentally hides a displayarea and nothing shows it again. mController.mValidateDisplayVis.add(da); 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/WindowManagerConstants.java b/services/core/java/com/android/server/wm/WindowManagerConstants.java index 3ad9b62ef058..9a5c8dffc0fc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerConstants.java +++ b/services/core/java/com/android/server/wm/WindowManagerConstants.java @@ -42,12 +42,23 @@ final class WindowManagerConstants { * <ul> * <li>false: applies to no apps (default)</li> * <li>true: applies to all apps</li> - * <li>large: applies to all apps but only on large screens</li> * </ul> */ private static final String KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST = "ignore_activity_orientation_request"; + /** + * The orientation of activity will be always "unspecified" except for game apps. + * <p>Possible values: + * <ul> + * <li>none: applies to no apps (default)</li> + * <li>all: applies to all apps ({@see #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST})</li> + * <li>large: applies to all apps but only on large screens</li> + * </ul> + */ + private static final String KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST_SCREENS = + "ignore_activity_orientation_request_screens"; + /** The packages that ignore {@link #KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST}. */ private static final String KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST = "opt_out_ignore_activity_orientation_request_list"; @@ -155,6 +166,7 @@ final class WindowManagerConstants { updateSystemGestureExclusionLogDebounceMillis(); break; case KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST: + case KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST_SCREENS: updateIgnoreActivityOrientationRequest(); break; case KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST: @@ -186,12 +198,16 @@ final class WindowManagerConstants { } private void updateIgnoreActivityOrientationRequest() { - final String value = mDeviceConfig.getProperty( + boolean allScreens = mDeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_WINDOW_MANAGER, + KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST, false); + String whichScreens = mDeviceConfig.getProperty( DeviceConfig.NAMESPACE_WINDOW_MANAGER, - KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST); - mIgnoreActivityOrientationRequestSmallScreen = Boolean.parseBoolean(value); - mIgnoreActivityOrientationRequestLargeScreen = mIgnoreActivityOrientationRequestSmallScreen - || ("large".equals(value)); + KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST_SCREENS); + allScreens |= ("all".equalsIgnoreCase(whichScreens)); + boolean largeScreens = allScreens || ("large".equalsIgnoreCase(whichScreens)); + mIgnoreActivityOrientationRequestSmallScreen = allScreens; + mIgnoreActivityOrientationRequestLargeScreen = largeScreens; } private void updateOptOutIgnoreActivityOrientationRequestList() { @@ -221,9 +237,9 @@ final class WindowManagerConstants { pw.print("="); pw.println(mSystemGestureExclusionLimitDp); pw.print(" "); pw.print(KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE); pw.print("="); pw.println(mSystemGestureExcludedByPreQStickyImmersive); - pw.print(" "); pw.print(KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST); - pw.print("="); pw.println(mIgnoreActivityOrientationRequestSmallScreen ? "true" - : mIgnoreActivityOrientationRequestLargeScreen ? "large" : "false"); + pw.print(" "); pw.print(KEY_IGNORE_ACTIVITY_ORIENTATION_REQUEST_SCREENS); + pw.print("="); pw.println(mIgnoreActivityOrientationRequestSmallScreen ? "all" + : mIgnoreActivityOrientationRequestLargeScreen ? "large" : "none"); if (mOptOutIgnoreActivityOrientationRequestPackages != null) { pw.print(" "); pw.print(KEY_OPT_OUT_IGNORE_ACTIVITY_ORIENTATION_REQUEST_LIST); pw.print("="); pw.println(mOptOutIgnoreActivityOrientationRequestPackages); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b42ce64fa1d2..58319f4cdabc 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; @@ -2672,7 +2673,7 @@ public class WindowManagerService extends IWindowManager.Stub if (outRelayoutResult != null) { if (win.syncNextBuffer() && viewVisibility == View.VISIBLE - && win.mSyncSeqId > lastSyncSeqId) { + && win.mSyncSeqId > lastSyncSeqId && !displayContent.mWaitingForConfig) { outRelayoutResult.syncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1; @@ -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/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 66921ff3adeb..fb197c566b7d 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1155,7 +1155,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } else if (!task.mCreatedByOrganizer) { throw new UnsupportedOperationException( "Cannot set non-organized task as adjacent flag root: " + wc); - } else if (task.getAdjacentTaskFragment() == null && !clearRoot) { + } else if (!task.hasAdjacentTaskFragment() && !clearRoot) { throw new UnsupportedOperationException( "Cannot set non-adjacent task as adjacent flag root: " + wc); } @@ -1645,9 +1645,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub opType, exception); break; } - if (taskFragment.getAdjacentTaskFragment() != secondaryTaskFragment) { + if (!taskFragment.isAdjacentTo(secondaryTaskFragment)) { // Only have lifecycle effect if the adjacent changed. - taskFragment.setAdjacentTaskFragment(secondaryTaskFragment); + if (Flags.allowMultipleAdjacentTaskFragments()) { + // Activity Embedding only set two TFs adjacent. + taskFragment.setAdjacentTaskFragments( + new TaskFragment.AdjacentSet(taskFragment, secondaryTaskFragment)); + } else { + taskFragment.setAdjacentTaskFragment(secondaryTaskFragment); + } effects |= TRANSACT_EFFECTS_LIFECYCLE; } @@ -1663,21 +1669,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub break; } case OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS: { - final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment(); - if (adjacentTaskFragment == null) { + if (!taskFragment.hasAdjacentTaskFragment()) { break; } - taskFragment.resetAdjacentTaskFragment(); - effects |= TRANSACT_EFFECTS_LIFECYCLE; - // Clear the focused app if the focused app is no longer visible after reset the - // adjacent TaskFragments. + // Check if the focused app is in the adjacent set that will be cleared. final ActivityRecord focusedApp = taskFragment.getDisplayContent().mFocusedApp; final TaskFragment focusedTaskFragment = focusedApp != null ? focusedApp.getTaskFragment() : null; - if ((focusedTaskFragment == taskFragment - || focusedTaskFragment == adjacentTaskFragment) + final boolean wasFocusedInAdjacent = focusedTaskFragment == taskFragment + || (focusedTaskFragment != null + && taskFragment.isAdjacentTo(focusedTaskFragment)); + + taskFragment.removeFromAdjacentTaskFragments(); + effects |= TRANSACT_EFFECTS_LIFECYCLE; + + // Clear the focused app if the focused app is no longer visible after reset the + // adjacent TaskFragments. + if (wasFocusedInAdjacent && !focusedTaskFragment.shouldBeVisible(null /* starting */)) { focusedTaskFragment.getDisplayContent().setFocusedApp(null /* newFocus */); } @@ -2191,26 +2201,60 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } private int setAdjacentRootsHierarchyOp(WindowContainerTransaction.HierarchyOp hop) { - final WindowContainer wc1 = WindowContainer.fromBinder(hop.getContainer()); - if (wc1 == null || !wc1.isAttached()) { - Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc1); - return TRANSACT_EFFECTS_NONE; - } - final TaskFragment root1 = wc1.asTaskFragment(); - final WindowContainer wc2 = WindowContainer.fromBinder(hop.getAdjacentRoot()); - if (wc2 == null || !wc2.isAttached()) { - Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc2); - return TRANSACT_EFFECTS_NONE; - } - final TaskFragment root2 = wc2.asTaskFragment(); - if (!root1.mCreatedByOrganizer || !root2.mCreatedByOrganizer) { - throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by" - + " organizer root1=" + root1 + " root2=" + root2); - } - if (root1.getAdjacentTaskFragment() == root2) { + if (!Flags.allowMultipleAdjacentTaskFragments()) { + final WindowContainer wc1 = WindowContainer.fromBinder(hop.getContainer()); + if (wc1 == null || !wc1.isAttached()) { + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc1); + return TRANSACT_EFFECTS_NONE; + } + final TaskFragment root1 = wc1.asTaskFragment(); + final WindowContainer wc2 = WindowContainer.fromBinder(hop.getAdjacentRoot()); + if (wc2 == null || !wc2.isAttached()) { + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc2); + return TRANSACT_EFFECTS_NONE; + } + final TaskFragment root2 = wc2.asTaskFragment(); + if (!root1.mCreatedByOrganizer || !root2.mCreatedByOrganizer) { + throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by" + + " organizer root1=" + root1 + " root2=" + root2); + } + if (root1.isAdjacentTo(root2)) { + return TRANSACT_EFFECTS_NONE; + } + root1.setAdjacentTaskFragment(root2); + return TRANSACT_EFFECTS_LIFECYCLE; + } + + final IBinder[] containers = hop.getContainers(); + final ArraySet<TaskFragment> adjacentRoots = new ArraySet<>(); + for (IBinder container : containers) { + final WindowContainer wc = WindowContainer.fromBinder(container); + if (wc == null || !wc.isAttached()) { + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc); + return TRANSACT_EFFECTS_NONE; + } + final Task root = wc.asTask(); + if (root == null) { + // Only support Task. Use WCT#setAdjacentTaskFragments for non-Task TaskFragment. + throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not called with" + + " Task. wc=" + wc); + } + if (!root.mCreatedByOrganizer) { + throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: Not created by" + + " organizer root=" + root); + } + if (adjacentRoots.contains(root)) { + throw new IllegalArgumentException("setAdjacentRootsHierarchyOp: called with same" + + " root twice=" + root); + } + adjacentRoots.add(root); + } + final TaskFragment root0 = adjacentRoots.valueAt(0); + final TaskFragment.AdjacentSet adjacentSet = new TaskFragment.AdjacentSet(adjacentRoots); + if (adjacentSet.equals(root0.getAdjacentTaskFragments())) { return TRANSACT_EFFECTS_NONE; } - root1.setAdjacentTaskFragment(root2); + root0.setAdjacentTaskFragments(adjacentSet); return TRANSACT_EFFECTS_LIFECYCLE; } @@ -2225,10 +2269,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub throw new IllegalArgumentException("clearAdjacentRootsHierarchyOp: Not created by" + " organizer root=" + root); } - if (root.getAdjacentTaskFragment() == null) { + if (!root.hasAdjacentTaskFragment()) { return TRANSACT_EFFECTS_NONE; } - root.resetAdjacentTaskFragment(); + root.removeFromAdjacentTaskFragments(); return TRANSACT_EFFECTS_LIFECYCLE; } 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/core/jni/com_android_server_am_Freezer.cpp b/services/core/jni/com_android_server_am_Freezer.cpp index 81487281dee7..e9a99f0fab64 100644 --- a/services/core/jni/com_android_server_am_Freezer.cpp +++ b/services/core/jni/com_android_server_am_Freezer.cpp @@ -68,7 +68,7 @@ jint getBinderFreezeInfo(JNIEnv *env, jobject, jint pid) { bool isFreezerSupported(JNIEnv *env, jclass) { std::string path; - if (!getAttributePathForTask("FreezerState", getpid(), &path)) { + if (!CgroupGetAttributePathForTask("FreezerState", getpid(), &path)) { ALOGI("No attribute for FreezerState"); return false; } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index 0c9a89bb0a30..8533eafaf9e0 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -114,7 +114,7 @@ public class CredentialManagerUi { /** Creates intent that is ot be invoked to cancel an in-progress UI session. */ public Intent createCancelIntent(IBinder requestId, String packageName) { return IntentFactory.createCancelUiIntent(mContext, requestId, - /*shouldShowCancellationUi=*/ true, packageName); + /*shouldShowCancellationUi=*/ true, packageName, mUserId); } /** @@ -177,7 +177,7 @@ public class CredentialManagerUi { IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForCredMan(mContext, requestInfo, providerDataList, - new ArrayList<>(disabledProviderDataList), mResultReceiver); + new ArrayList<>(disabledProviderDataList), mResultReceiver, mUserId); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); Intent intent = intentCreationResult.getIntent(); @@ -211,7 +211,7 @@ public class CredentialManagerUi { RequestSessionMetric requestSessionMetric) { IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForAutofill(mContext, requestInfo, new ArrayList<>(), - mResultReceiver); + mResultReceiver, mUserId); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); return intentCreationResult.getIntent(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 4d318f9036eb..2627895b8c63 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -9089,7 +9089,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { CallerIdentity caller = getCallerIdentity(who); if (Flags.setAutoTimeEnabledCoexistence()) { - Preconditions.checkCallAuthorization(hasPermission(SET_TIME, caller.getPackageName())); + Preconditions.checkCallAuthorization(hasPermission(SET_TIME, callerPackageName)); } else { Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) @@ -9152,7 +9152,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( /* who */ null, SET_TIME, - caller.getPackageName(), + callerPackageName, UserHandle.USER_ALL ); Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin( @@ -9197,7 +9197,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { CallerIdentity caller = getCallerIdentity(who); if (Flags.setAutoTimeZoneEnabledCoexistence()) { Preconditions.checkCallAuthorization( - hasPermission(SET_TIME_ZONE, caller.getPackageName())); + hasPermission(SET_TIME_ZONE, callerPackageName)); } else { Objects.requireNonNull(who, "ComponentName is null"); Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) @@ -9255,7 +9255,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( /* who */ null, SET_TIME_ZONE, - caller.getPackageName(), + callerPackageName, UserHandle.USER_ALL ); Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin( 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/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig index 4412968999e5..0d222fb4409e 100644 --- a/services/java/com/android/server/flags.aconfig +++ b/services/java/com/android/server/flags.aconfig @@ -10,14 +10,6 @@ flag { } flag { - name: "remove_java_service_manager_cache" - namespace: "system_performance" - description: "This flag turns off Java's Service Manager caching mechanism." - bug: "333854840" - is_fixed_read_only: true -} - -flag { name: "remove_text_service" namespace: "wear_frameworks" description: "Remove TextServiceManagerService on Wear" diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java index 5492ba6b9dd1..6e14bad11837 100644 --- a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java +++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import android.os.instrumentation.MethodDescriptor; +import android.os.instrumentation.MethodDescriptorParser; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -37,7 +38,7 @@ import java.lang.reflect.Method; /** * Test class for - * {@link DynamicInstrumentationManagerService#parseMethodDescriptor(ClassLoader, + * {@link MethodDescriptorParser#parseMethodDescriptor(ClassLoader, * MethodDescriptor)}. * <p> * Build/Install/Run: @@ -119,13 +120,13 @@ public class ParseMethodDescriptorTest { } private Method parseMethodDescriptor(String fqcn, String methodName) { - return DynamicInstrumentationManagerService.parseMethodDescriptor( + return MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), getMethodDescriptor(fqcn, methodName, new String[]{})); } private Method parseMethodDescriptor(String fqcn, String methodName, String[] fqParameters) { - return DynamicInstrumentationManagerService.parseMethodDescriptor( + return MethodDescriptorParser.parseMethodDescriptor( getClass().getClassLoader(), getMethodDescriptor(fqcn, methodName, fqParameters)); } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java index acd34e323dc2..0ae7699aeb71 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java @@ -233,6 +233,6 @@ public class BroadcastHelperTest { mBroadcastHelper.sendPackageChangedBroadcast(mMockSnapshot, PACKAGE_CHANGED_TEST_PACKAGE_NAME, true /* dontKillApp */, componentNames, - UserHandle.USER_SYSTEM, "test" /* reason */); + UserHandle.USER_SYSTEM, "test" /* reason */, "test" /* reasonForTrace */); } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index 365cbaed2aac..724f083018f2 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -3708,7 +3708,7 @@ public class DisplayManagerServiceTest { eq(config)); bs.releaseVirtualDisplay(mMockAppToken); - verify(mMockVirtualDisplayAdapter).releaseVirtualDisplayLocked(binder, callingUid); + verify(mMockVirtualDisplayAdapter).releaseVirtualDisplayLocked(binder); } @Test diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index 91f1aaf603e6..8ca39194de3b 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -2471,6 +2471,26 @@ public final class DisplayPowerControllerTest { eq(false)); } + @Test + public void onDisplayChange_canceledAfterStop() { + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + + // stop the dpc (turn it down) + mHolder.dpc.stop(); + advanceTime(1); + + // To trigger all the changes that can happen, we will completely change the underlying + // display device. + setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), + mock(DisplayDeviceConfig.class), /* isEnabled= */ true); + + // Call onDisplayChange after we stopped DPC and make sure it doesn't crash + mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); + advanceTime(1); + + // No crash = success + } + /** * Creates a mock and registers it to {@link LocalServices}. */ diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java index dbd5c65f9ba3..9287b3004279 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java @@ -118,14 +118,13 @@ public class VirtualDisplayAdapterTest { public void testCreateAndReleaseVirtualDisplay() { VirtualDisplayConfig config = new VirtualDisplayConfig.Builder("test", /* width= */ 1, /* height= */ 1, /* densityDpi= */ 1).build(); - int ownerUid = 10; DisplayDevice result = mAdapter.createVirtualDisplayLocked(mMockCallback, - /* projection= */ null, ownerUid, /* packageName= */ "testpackage", + /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage", /* uniqueId= */ "uniqueId", /* surface= */ null, /* flags= */ 0, config); assertNotNull(result); - result = mAdapter.releaseVirtualDisplayLocked(mMockBinder, ownerUid); + result = mAdapter.releaseVirtualDisplayLocked(mMockBinder); assertNotNull(result); } @@ -230,7 +229,6 @@ public class VirtualDisplayAdapterTest { // Displays for the same package for (int i = 0; i < MAX_DEVICES_PER_PACKAGE * 2; i++) { - // Same owner UID IVirtualDisplayCallback callback = createCallback(); DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, 1234, "test.package", "123", @@ -240,7 +238,6 @@ public class VirtualDisplayAdapterTest { // Displays for different packages for (int i = 0; i < MAX_DEVICES * 2; i++) { - // Same owner UID IVirtualDisplayCallback callback = createCallback(); DisplayDevice device = mAdapter.createVirtualDisplayLocked(callback, mMediaProjectionMock, 1234 + i, "test.package", "123", @@ -270,8 +267,7 @@ public class VirtualDisplayAdapterTest { } // Release one display - DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(), - ownerUid); + DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder()); assertNotNull(device); callbacks.remove(0); @@ -292,7 +288,7 @@ public class VirtualDisplayAdapterTest { // Release all the displays for (IVirtualDisplayCallback cb : callbacks) { - device = mAdapter.releaseVirtualDisplayLocked(cb.asBinder(), ownerUid); + device = mAdapter.releaseVirtualDisplayLocked(cb.asBinder()); assertNotNull(device); } callbacks.clear(); @@ -342,8 +338,7 @@ public class VirtualDisplayAdapterTest { } // Release one display - DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder(), - firstOwnerUid); + DisplayDevice device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(0).asBinder()); assertNotNull(device); callbacks.remove(0); @@ -363,9 +358,8 @@ public class VirtualDisplayAdapterTest { assertNull(device); // Release all the displays - for (int i = 0; i < callbacks.size(); i++) { - device = mAdapter.releaseVirtualDisplayLocked(callbacks.get(i).asBinder(), - firstOwnerUid + i); + for (IVirtualDisplayCallback iVirtualDisplayCallback : callbacks) { + device = mAdapter.releaseVirtualDisplayLocked(iVirtualDisplayCallback.asBinder()); assertNotNull(device); } callbacks.clear(); diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/RejectedModesVoteTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/RejectedModesVoteTest.kt new file mode 100644 index 000000000000..dd3211d0ef83 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/RejectedModesVoteTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.mode + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class RejectedModesVoteTest { + private val rejectedModes = setOf(1, 2) + + private val otherMode = 2 + + private lateinit var rejectedModesVote: RejectedModesVote + + @Before + fun setUp() { + rejectedModesVote = RejectedModesVote(rejectedModes) + } + + @Test + fun addsRejectedModeIds_summaryIsEmpty() { + val summary = createVotesSummary() + + rejectedModesVote.updateSummary(summary) + + assertThat(summary.rejectedModeIds).containsExactlyElementsIn(rejectedModes) + } + + @Test + fun addsRejectedModeIds_summaryIsNotEmpty() { + val summary = createVotesSummary() + summary.rejectedModeIds.add(otherMode) + + rejectedModesVote.updateSummary(summary) + + assertThat(summary.rejectedModeIds).containsExactlyElementsIn(rejectedModes + otherMode) + } +}
\ No newline at end of file diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt index 239e59b69187..958cf21a38a2 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VoteSummaryTest.kt @@ -186,6 +186,44 @@ class VoteSummaryTest { assertThat(result).hasSize(1) } + + enum class RejectedModesTestCase( + internal val summaryRejectedModes: Set<Int>?, + val modesToFilter: Array<Display.Mode>, + val expectedModeIds: Set<Int> + ) { + HAS_NO_MATCHING_VOTE( + setOf(4, 5), + arrayOf(createMode(1, 90f, 90f), + createMode(2, 90f, 60f), + createMode(3, 60f, 90f)), + setOf(1, 2, 3) + ), + HAS_SINGLE_MATCHING_VOTE( + setOf(1), + arrayOf(createMode(1, 90f, 90f), + createMode(2, 90f, 60f), + createMode(3, 60f, 90f)), + setOf(2, 3) + ), + HAS_MULTIPLE_MATCHING_VOTES( + setOf(1, 2), + arrayOf(createMode(1, 90f, 90f), + createMode(2, 90f, 60f), + createMode(3, 60f, 90f)), + setOf(3) + ), + } + + @Test + fun testFilterModes_rejectedModes(@TestParameter testCase: RejectedModesTestCase) { + val summary = createSummary() + summary.rejectedModeIds = testCase.summaryRejectedModes + + val result = summary.filterModes(testCase.modesToFilter) + + assertThat(result.map {it.modeId}).containsExactlyElementsIn(testCase.expectedModeIds) + } } diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java index 874e99173c63..495e853370ee 100644 --- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java +++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java @@ -46,7 +46,6 @@ import android.os.RemoteException; import android.os.test.TestLooper; import android.service.dreams.IDreamService; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -108,10 +107,8 @@ public class DreamControllerTest { .thenReturn(Context.ACTIVITY_TASK_SERVICE); final PowerManager powerManager = new PowerManager(mContext, mPowerManager, null, null); - when(mContext.getSystemService(Context.POWER_SERVICE)) + when(mContext.getSystemService(PowerManager.class)) .thenReturn(powerManager); - when(mContext.getSystemServiceName(PowerManager.class)) - .thenReturn(Context.POWER_SERVICE); when(mContext.getResources()).thenReturn(mResources); mToken = new Binder(); @@ -234,8 +231,13 @@ public class DreamControllerTest { } @Test - @FlakyTest(bugId = 293109503) public void serviceDisconnect_resetsScreenTimeout() throws RemoteException { + when(mResources.getBoolean( + com.android.internal.R.bool.config_resetScreenTimeoutOnUnexpectedDreamExit)) + .thenReturn(true); + // Recreate DreamManager because the configuration gets retrieved in the constructor + mDreamController = new DreamController(mContext, mHandler, mListener); + // Start dream. mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); @@ -254,8 +256,13 @@ public class DreamControllerTest { } @Test - @FlakyTest(bugId = 293109503) public void binderDied_resetsScreenTimeout() throws RemoteException { + when(mResources.getBoolean( + com.android.internal.R.bool.config_resetScreenTimeoutOnUnexpectedDreamExit)) + .thenReturn(true); + // Recreate DreamManager because the configuration gets retrieved in the constructor + mDreamController = new DreamController(mContext, mHandler, mListener); + // Start dream. mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); 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/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java index 0304a74f7654..cd8d415bdfa2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java @@ -21,11 +21,7 @@ import static android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.SharedLibraryInfo; @@ -90,32 +86,15 @@ public class InstallDependencyHelperTest { } @Test - public void testResolveLibraryDependenciesIfNeeded_errorInSharedLibrariesImpl() - throws Exception { - doThrow(new PackageManagerException(new Exception("xyz"))) - .when(mSharedLibraries).collectMissingSharedLibraryInfos(any()); - - PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2); - CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, - 0, mHandler, callback); - callback.assertFailure(); - - assertThat(callback.error).hasMessageThat().contains("xyz"); - } - - @Test public void testResolveLibraryDependenciesIfNeeded_failsToBind() throws Exception { // Return a non-empty list as missing dependency PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2); List<SharedLibraryInfo> missingDependency = Collections.singletonList( mock(SharedLibraryInfo.class)); - when(mSharedLibraries.collectMissingSharedLibraryInfos(eq(pkg))) - .thenReturn(missingDependency); CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, - 0, mHandler, callback); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(missingDependency, pkg, + mComputer, 0, mHandler, callback); callback.assertFailure(); assertThat(callback.error).hasMessageThat().contains( @@ -128,12 +107,10 @@ public class InstallDependencyHelperTest { // Return an empty list as missing dependency PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2); List<SharedLibraryInfo> missingDependency = Collections.emptyList(); - when(mSharedLibraries.collectMissingSharedLibraryInfos(eq(pkg))) - .thenReturn(missingDependency); CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ true); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, - 0, mHandler, callback); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(missingDependency, pkg, + mComputer, 0, mHandler, callback); callback.assertSuccess(); } 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/ondeviceintelligencetests/Android.bp b/services/tests/ondeviceintelligencetests/Android.bp index a31a3fb65700..f235da2fea7f 100644 --- a/services/tests/ondeviceintelligencetests/Android.bp +++ b/services/tests/ondeviceintelligencetests/Android.bp @@ -44,14 +44,18 @@ android_test { "truth", "frameworks-base-testutils", "androidx.test.rules", - ], + ] + select(soong_config_variable("ANDROID", "release_ondevice_intelligence_module"), { + "true": [ + "service-ondeviceintelligence.impl", + ], + default: [], + }), libs: [ "android.test.mock.stubs.system", "android.test.base.stubs.system", "android.test.runner.stubs.system", ], - certificate: "platform", platform_apis: true, test_suites: ["device-tests"], diff --git a/services/tests/ondeviceintelligencetests/OWNERS b/services/tests/ondeviceintelligencetests/OWNERS index 09774f78d712..a4fc7582a785 100644 --- a/services/tests/ondeviceintelligencetests/OWNERS +++ b/services/tests/ondeviceintelligencetests/OWNERS @@ -1 +1,3 @@ -file:/core/java/android/app/ondeviceintelligence/OWNERS +shiqing@google.com +sandeepbandaru@google.com +shivanker@google.com diff --git a/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java b/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java index d12579cd6b11..28ccb84c38f3 100644 --- a/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java +++ b/services/tests/ondeviceintelligencetests/src/com/android/server/ondeviceintelligence/InferenceInfoStoreTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat; import android.app.ondeviceintelligence.InferenceInfo; import android.os.Bundle; import android.os.PersistableBundle; -import android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService; import android.util.Base64; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -38,6 +37,8 @@ import java.util.List; public class InferenceInfoStoreTest { InferenceInfoStore inferenceInfoStore; + public static final String INFERENCE_INFO_BUNDLE_KEY = "inference_info"; + @Before public void setUp() { inferenceInfoStore = new InferenceInfoStore(1000); @@ -46,7 +47,7 @@ public class InferenceInfoStoreTest { @Test public void testInferenceInfoParsesFromBundleSuccessfully() throws Exception { Bundle bundle = new Bundle(); - bundle.putByteArray(OnDeviceSandboxedInferenceService.INFERENCE_INFO_BUNDLE_KEY, + bundle.putByteArray(INFERENCE_INFO_BUNDLE_KEY, getInferenceInfoBytes(1, 1, 100)); inferenceInfoStore.addInferenceInfoFromBundle(bundle); List<InferenceInfo> inferenceInfos = inferenceInfoStore.getLatestInferenceInfo(0); @@ -59,7 +60,7 @@ public class InferenceInfoStoreTest { @Test public void testInferenceInfoParsesFromPersistableBundleSuccessfully() throws Exception { PersistableBundle bundle = new PersistableBundle(); - bundle.putString(OnDeviceSandboxedInferenceService.INFERENCE_INFO_BUNDLE_KEY, + bundle.putString(INFERENCE_INFO_BUNDLE_KEY, Base64.encodeToString(getInferenceInfoBytes(1, 1, 100), Base64.DEFAULT)); inferenceInfoStore.addInferenceInfoFromBundle(bundle); List<InferenceInfo> inferenceInfos = inferenceInfoStore.getLatestInferenceInfo(0); @@ -74,11 +75,11 @@ public class InferenceInfoStoreTest { public void testEvictionAfterMaxAge() throws Exception { PersistableBundle bundle = new PersistableBundle(); long testStartTime = System.currentTimeMillis(); - bundle.putString(OnDeviceSandboxedInferenceService.INFERENCE_INFO_BUNDLE_KEY, + bundle.putString(INFERENCE_INFO_BUNDLE_KEY, Base64.encodeToString(getInferenceInfoBytes(1, testStartTime - 10, testStartTime + 100), Base64.DEFAULT)); inferenceInfoStore.addInferenceInfoFromBundle(bundle); - bundle.putString(OnDeviceSandboxedInferenceService.INFERENCE_INFO_BUNDLE_KEY, + bundle.putString(INFERENCE_INFO_BUNDLE_KEY, Base64.encodeToString(getInferenceInfoBytes(1, testStartTime - 5, testStartTime + 100), Base64.DEFAULT)); inferenceInfoStore.addInferenceInfoFromBundle(bundle); diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index 7248833d876c..b166514ce0b9 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -64,6 +64,7 @@ import android.os.Binder; import android.os.CpuHeadroomParamsInternal; import android.os.GpuHeadroomParamsInternal; import android.os.IBinder; +import android.os.IHintManager; import android.os.IHintSession; import android.os.PerformanceHintManager; import android.os.Process; @@ -154,6 +155,8 @@ public class HintManagerServiceTest { private ActivityManagerInternal mAmInternalMock; @Mock private PackageManager mMockPackageManager; + @Mock + private IHintManager.IHintManagerClient mClientCallback; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @@ -171,6 +174,23 @@ public class HintManagerServiceTest { }; } + private SupportInfo makeDefaultSupportInfo() { + mSupportInfo = new SupportInfo(); + mSupportInfo.usesSessions = true; + // By default, mark everything as fully supported + mSupportInfo.sessionHints = -1; + mSupportInfo.sessionModes = -1; + mSupportInfo.modes = -1; + mSupportInfo.boosts = -1; + mSupportInfo.sessionTags = -1; + mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); + mSupportInfo.headroom.isCpuSupported = true; + mSupportInfo.headroom.cpuMinIntervalMillis = 2000; + mSupportInfo.headroom.isGpuSupported = true; + mSupportInfo.headroom.gpuMinIntervalMillis = 2000; + return mSupportInfo; + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -181,12 +201,7 @@ public class HintManagerServiceTest { mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>(); ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.category = ApplicationInfo.CATEGORY_GAME; - mSupportInfo = new SupportInfo(); - mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo(); - mSupportInfo.headroom.isCpuSupported = true; - mSupportInfo.headroom.cpuMinIntervalMillis = 2000; - mSupportInfo.headroom.isGpuSupported = true; - mSupportInfo.headroom.gpuMinIntervalMillis = 2000; + mSupportInfo = makeDefaultSupportInfo(); when(mContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME); when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt())) @@ -215,6 +230,7 @@ public class HintManagerServiceTest { when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); + when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); } @@ -409,8 +425,11 @@ public class HintManagerServiceTest { HintManagerService service = createService(); IBinder token = new Binder(); - final int threadCount = - service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + + final int threadCount = data.maxGraphicsPipelineThreads; + long sessionPtr1 = 1111L; long sessionId1 = 11111L; CountDownLatch stopLatch1 = new CountDownLatch(1); @@ -1400,4 +1419,67 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); } + + @Test + public void testRegisteringClient() throws Exception { + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo, mSupportInfo); + } + + @Test + public void testRegisteringClientOnV4() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(4); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, true); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 31); + assertEquals(data.supportInfo.sessionModes, 0); + assertEquals(data.supportInfo.sessionTags, 0); + assertEquals(data.powerHalVersion, 4); + assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); + } + + @Test + public void testRegisteringClientOnV5() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, true); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 255); + assertEquals(data.supportInfo.sessionModes, 1); + assertEquals(data.supportInfo.sessionTags, 31); + assertEquals(data.powerHalVersion, 5); + assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE); + } + + @Test + public void testSettingUpOldClientWhenUnsupported() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + // Mock unsupported to modify the default support behavior + when(mNativeWrapperMock.halGetHintSessionPreferredRate()) + .thenReturn(-1L); + HintManagerService service = createService(); + IHintManager.HintManagerClientData data = service.getBinderServiceInstance() + .registerClient(mClientCallback); + assertNotNull(data); + assertEquals(data.supportInfo.usesSessions, false); + assertEquals(data.supportInfo.boosts, 0); + assertEquals(data.supportInfo.modes, 0); + assertEquals(data.supportInfo.sessionHints, 0); + assertEquals(data.supportInfo.sessionModes, 0); + assertEquals(data.supportInfo.sessionTags, 0); + assertEquals(data.powerHalVersion, 5); + assertEquals(data.preferredRateNanos, -1); + } } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java index f312bedca82c..3bdbcb50e601 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsAggregatorTest.java @@ -263,6 +263,34 @@ public class PowerStatsAggregatorTest { }); } + @Test + public void emptyHistory() { + PowerStats.Descriptor descriptor = new PowerStats.Descriptor(TEST_POWER_COMPONENT, + "majorDrain", 1, null, 0, 1, new PersistableBundle()); + PowerStats powerStats = new PowerStats(descriptor); + + mHistory.forceRecordAllHistory(); + + advance(1000); + + long firstItemTimestamp = mMonotonicClock.monotonicTime(); + powerStats.stats = new long[]{24}; + mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats); + + advance(1000); + + long secondItemTimestamp = mMonotonicClock.monotonicTime(); + powerStats.stats = new long[]{42}; + mHistory.recordPowerStats(mClock.realtime, mClock.uptime, powerStats); + + mAggregator.aggregatePowerStats(mHistory, firstItemTimestamp + 1, secondItemTimestamp, + stats -> { + mAggregatedStatsCount++; + }); + + assertThat(mAggregatedStatsCount).isEqualTo(0); + } + private void advance(long durationMs) { mClock.realtime += durationMs; mClock.uptime += durationMs; diff --git a/services/tests/security/intrusiondetection/AndroidManifest.xml b/services/tests/security/intrusiondetection/AndroidManifest.xml index 6460a32efc4f..d58e0d84ee32 100644 --- a/services/tests/security/intrusiondetection/AndroidManifest.xml +++ b/services/tests/security/intrusiondetection/AndroidManifest.xml @@ -23,15 +23,6 @@ <application android:testOnly="true" android:debuggable="true" android:usesCleartextTraffic="true"> <uses-library android:name="android.test.runner"/> - <receiver android:name="com.android.server.security.intrusiondetection.IntrusionDetectionAdminReceiver" - android:permission="android.permission.BIND_DEVICE_ADMIN" - android:exported="true"> - <meta-data android:name="android.app.device_admin" - android:resource="@xml/device_admin"/> - <intent-filter> - <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/> - </intent-filter> - </receiver> </application> <queries> diff --git a/services/tests/security/intrusiondetection/res/xml/device_admin.xml b/services/tests/security/intrusiondetection/res/xml/device_admin.xml deleted file mode 100644 index f8cd8f0b9b44..000000000000 --- a/services/tests/security/intrusiondetection/res/xml/device_admin.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2024 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<device-admin xmlns:android="http://schemas.android.com/apk/res/android"> -</device-admin> diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java index 1380a6fec94f..5cba6b2c3e67 100644 --- a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java +++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/IntrusionDetectionServiceTest.java @@ -16,13 +16,12 @@ package com.android.server.security.intrusiondetection; +import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE; import static android.Manifest.permission.INTERNET; import static android.Manifest.permission.MANAGE_INTRUSION_DETECTION_STATE; import static android.Manifest.permission.READ_INTRUSION_DETECTION_STATE; -import static android.Manifest.permission.BIND_INTRUSION_DETECTION_EVENT_TRANSPORT_SERVICE; 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.assertThrows; @@ -45,9 +44,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.Manifest; import android.os.IBinder; -import android.os.Bundle; import android.os.Looper; import android.os.PermissionEnforcer; import android.os.RemoteException; @@ -63,17 +60,13 @@ import android.util.Log; import androidx.test.core.app.ApplicationProvider; import com.android.bedstead.harrier.BedsteadJUnit4; -import com.android.bedstead.harrier.annotations.AfterClass; -import com.android.bedstead.harrier.annotations.BeforeClass; import com.android.bedstead.multiuser.annotations.RequireRunOnSystemUser; import com.android.bedstead.nene.TestApis; import com.android.bedstead.nene.devicepolicy.DeviceOwner; -import com.android.bedstead.nene.exceptions.NeneException; import com.android.bedstead.permissions.CommonPermissions; import com.android.bedstead.permissions.PermissionContext; import com.android.bedstead.permissions.annotations.EnsureHasPermission; import com.android.coretests.apps.testapp.LocalIntrusionDetectionEventTransport; -import com.android.internal.infra.AndroidFuture; import com.android.server.ServiceThread; import org.junit.Before; @@ -131,28 +124,6 @@ public class IntrusionDetectionServiceTest { "com.android.coretests.apps.testapp"; private static final String TEST_SERVICE = TEST_PKG + ".TestLoggingService"; - @BeforeClass - public static void setDeviceOwner() { - ComponentName admin = - new ComponentName( - ApplicationProvider.getApplicationContext(), - IntrusionDetectionAdminReceiver.class); - try { - sDeviceOwner = TestApis.devicePolicy().setDeviceOwner(admin); - } catch (NeneException e) { - fail("Failed to set device owner " + admin.flattenToString() + ": " + e); - } - } - - @AfterClass - public static void removeDeviceOwner() { - try { - sDeviceOwner.remove(); - } catch (NeneException e) { - fail("Failed to remove device owner : " + e); - } - } - @SuppressLint("VisibleForTests") @Before public void setUp() throws Exception { @@ -181,6 +152,7 @@ public class IntrusionDetectionServiceTest { } @Test + @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testRemoveStateCallback_NoPermission() { mPermissionEnforcer.revoke(READ_INTRUSION_DETECTION_STATE); StateCallback scb = new StateCallback(); @@ -232,6 +204,7 @@ public class IntrusionDetectionServiceTest { } @Test + @Ignore("Unit test does not run as system service UID") public void testRemoveStateCallback() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); @@ -242,7 +215,6 @@ public class IntrusionDetectionServiceTest { assertEquals(STATE_DISABLED, scb1.mState); assertEquals(STATE_DISABLED, scb2.mState); - doReturn(true).when(mDataAggregator).initialize(); doReturn(true).when(mIntrusionDetectionEventTransportConnection).initialize(); mIntrusionDetectionService.getBinderService().removeStateCallback(scb2); @@ -255,6 +227,7 @@ public class IntrusionDetectionServiceTest { assertNull(ccb.mErrorCode); } + @Ignore("Unit test does not run as system service UID") @Test public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException { mIntrusionDetectionService.setState(STATE_DISABLED); @@ -415,39 +388,13 @@ public class IntrusionDetectionServiceTest { } @Test - @RequireRunOnSystemUser - public void testDataSources_Initialize_HasDeviceOwner() throws Exception { - NetworkLogSource networkLogSource = new NetworkLogSource(mContext, mDataAggregator); - SecurityLogSource securityLogSource = new SecurityLogSource(mContext, mDataAggregator); - - assertTrue(networkLogSource.initialize()); - assertTrue(securityLogSource.initialize()); - } - - @Test - @RequireRunOnSystemUser - public void testDataSources_Initialize_NoDeviceOwner() throws Exception { - NetworkLogSource networkLogSource = new NetworkLogSource(mContext, mDataAggregator); - SecurityLogSource securityLogSource = new SecurityLogSource(mContext, mDataAggregator); - ComponentName admin = sDeviceOwner.componentName(); - - try { - sDeviceOwner.remove(); - assertFalse(networkLogSource.initialize()); - assertFalse(securityLogSource.initialize()); - } finally { - sDeviceOwner = TestApis.devicePolicy().setDeviceOwner(admin); - } - } - - @Test + @Ignore("Unit test does not run as system service UID") @RequireRunOnSystemUser @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddSecurityEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); - assertTrue(mDataAggregator.initialize()); // SecurityLogging generates a number of events and callbacks, so create a latch to wait for // the given event. @@ -491,12 +438,12 @@ public class IntrusionDetectionServiceTest { @Test @RequireRunOnSystemUser + @Ignore("Unit test does not run as system service UID") @EnsureHasPermission(CommonPermissions.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void testDataAggregator_AddNetworkEvent() throws Exception { mIntrusionDetectionService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); - assertTrue(mDataAggregator.initialize()); // Network logging may log multiple and callbacks, so create a latch to wait for // the given event. 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/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 0404b82d306d..c4b8599a483c 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -118,6 +118,7 @@ import org.mockito.Spy; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -232,7 +233,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { any(AlarmManager.OnAlarmListener.class), any(Handler.class)); doAnswer(inv -> { - mCustomListener = () -> {}; + mCustomListener = () -> { + }; return null; }).when(mAlarmManager).cancel(eq(mCustomListener)); when(mContext.getSystemService(eq(Context.POWER_SERVICE))) @@ -1321,7 +1323,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { @Test public void enableCarMode_failsForBogusPackageName() throws Exception { when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt())) - .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1); + .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1); assertThrows(SecurityException.class, () -> mService.enableCarMode(0, 0, PACKAGE_NAME)); assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR); @@ -1343,19 +1345,19 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { @Test public void disableCarMode_failsForBogusPackageName() throws Exception { when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt())) - .thenReturn(TestInjector.DEFAULT_CALLING_UID); + .thenReturn(TestInjector.DEFAULT_CALLING_UID); mService.enableCarMode(0, 0, PACKAGE_NAME); assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR); when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt())) - .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1); + .thenReturn(TestInjector.DEFAULT_CALLING_UID + 1); assertThrows(SecurityException.class, - () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME)); + () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME)); assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR); // Clean up when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt())) - .thenReturn(TestInjector.DEFAULT_CALLING_UID); + .thenReturn(TestInjector.DEFAULT_CALLING_UID); mService.disableCarModeByCallingPackage(0, PACKAGE_NAME); assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR); } @@ -1473,12 +1475,13 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { assertFalse(mUiManagerService.getConfiguration().isNightModeActive()); } - // attention modes with expected night modes - Map<Integer, Boolean> modes = Map.of( - MODE_ATTENTION_THEME_OVERLAY_OFF, initialNightMode, - MODE_ATTENTION_THEME_OVERLAY_DAY, false, - MODE_ATTENTION_THEME_OVERLAY_NIGHT, true - ); + // Attention modes with expected night modes. + // Important to keep modes.put(MODE_ATTENTION_THEME_OVERLAY_OFF, initialNightMode) in the + // first position, hence LinkedHashMap. + Map<Integer, Boolean> modes = new LinkedHashMap<>(); + modes.put(MODE_ATTENTION_THEME_OVERLAY_OFF, initialNightMode); + modes.put(MODE_ATTENTION_THEME_OVERLAY_DAY, false); + modes.put(MODE_ATTENTION_THEME_OVERLAY_NIGHT, true); // test for (int attentionMode : modes.keySet()) { @@ -1562,7 +1565,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { private final int callingUid; public TestInjector() { - this(DEFAULT_CALLING_UID); + this(DEFAULT_CALLING_UID); } public TestInjector(int callingUid) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 90bf1d36a4ce..074cbb57d5b7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -49,10 +49,14 @@ import static android.app.NotificationChannel.PROMOTIONS_ID; import static android.app.NotificationChannel.RECS_ID; import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; +import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; +import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; +import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; @@ -369,6 +373,7 @@ import java.io.FileOutputStream; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -11273,19 +11278,71 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); } + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception { + mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged( + mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED)); + + Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED) + .setPackage("rule.owner.pkg") + .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id") + .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + + verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); + } + private static Intent eqIntent(Intent wanted) { return ArgumentMatchers.argThat( new ArgumentMatcher<Intent>() { @Override public boolean matches(Intent argument) { return wanted.filterEquals(argument) - && wanted.getFlags() == argument.getFlags(); + && wanted.getFlags() == argument.getFlags() + && equalBundles(wanted.getExtras(), argument.getExtras()); } @Override public String toString() { return wanted.toString(); } + + private boolean equalBundles(Bundle one, Bundle two) { + if (one == null && two == null) { + return true; + } + if ((one == null) != (two == null)) { + return false; + } + if (one.size() != two.size()) { + return false; + } + + HashSet<String> setOne = new HashSet<>(one.keySet()); + setOne.addAll(two.keySet()); + + for (String key : setOne) { + if (!one.containsKey(key) || !two.containsKey(key)) { + return false; + } + + Object valueOne = one.get(key); + Object valueTwo = two.get(key); + if (valueOne instanceof Bundle + && valueTwo instanceof Bundle + && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { + return false; + } else if (valueOne == null) { + if (valueTwo != null) { + return false; + } + } else if (!valueOne.equals(valueTwo)) { + return false; + } + } + return true; + } }); } @@ -17314,6 +17371,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); @@ -17327,6 +17385,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, @@ -17339,6 +17398,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0, @@ -17388,6 +17448,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); @@ -17420,6 +17481,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); @@ -17434,6 +17496,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); @@ -17483,6 +17546,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post .build(); @@ -17515,6 +17579,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, n, UserHandle.getUserHandleForUid(mUid), null, 0); @@ -17543,6 +17608,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, @@ -17570,6 +17636,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) .setColor(Color.WHITE) .setColorized(true) + .setOngoing(true) .build(); StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java index 65ed7b6e622d..934c33b7f1f1 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RateEstimatorTest.java @@ -19,6 +19,8 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.HOURS; +import android.service.notification.RateEstimator; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml index 787f4e85c012..cbbbc731753d 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" /> @@ -56,7 +48,7 @@ <bookmark category="android.intent.category.APP_CONTACTS" - androidprv:keycode="KEYCODE_C" + androidprv:keycode="KEYCODE_P" androidprv:modifierState="META|SHIFT" /> <bookmark 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 1e9038ee1769..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 @@ -468,6 +461,14 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { } @Test + public void testKeyGestureLaunchVoiceAssistant() { + Assert.assertTrue( + sendKeyGestureEventComplete( + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT)); + mPhoneWindowManager.assertSearchManagerLaunchAssist(); + } + + @Test public void testKeyGestureGoHome() { Assert.assertTrue( sendKeyGestureEventComplete(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)); 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/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index d4a921c5f00a..1b0d9dc3b170 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -554,6 +554,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testSetRequestedOrientationUpdatesConfiguration() throws Exception { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity = new ActivityBuilder(mAtm) .setCreateTask(true) .setConfigChanges(ORIENTATION_CONFIG_CHANGES) @@ -641,6 +642,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void ignoreRequestedOrientationForResizableInSplitWindows() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity = createActivityWith2LevelTask(); final Task task = activity.getTask(); final Task rootTask = activity.getRootTask(); @@ -685,6 +687,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void respectRequestedOrientationForNonResizableInSplitWindows() { + mDisplayContent.setIgnoreOrientationRequest(false); final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); spyOn(tda); doReturn(true).when(tda).supportsNonResizableMultiWindow(); @@ -1906,6 +1909,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testActivityOnCancelFixedRotationTransform() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity = createActivityWithTask(); final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); final RemoteDisplayChangeController remoteDisplayChangeController = activity @@ -2054,6 +2058,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testFixedRotationSnapshotStartingWindow() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity = createActivityWithTask(); // TaskSnapshotSurface requires a fullscreen opaque window. final WindowManager.LayoutParams params = new WindowManager.LayoutParams( @@ -2278,6 +2283,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testSupportsFreeform() { final ActivityRecord activity = new ActivityBuilder(mAtm) + .setComponent(getUniqueComponentName(mContext.getPackageName())) .setCreateTask(true) .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) @@ -2410,6 +2416,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testOrientationForScreenOrientationBehind() { + mDisplayContent.setIgnoreOrientationRequest(false); final Task task = createTask(mDisplayContent); // Activity below new ActivityBuilder(mAtm) @@ -2507,6 +2514,7 @@ public class ActivityRecordTests extends WindowTestsBase { @SetupWindows(addWindows = W_ACTIVITY) @Test public void testLandscapeSeascapeRotationByApp() { + mDisplayContent.setIgnoreOrientationRequest(false); final Task task = new TaskBuilder(mSupervisor) .setDisplay(mDisplayContent).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); @@ -2572,6 +2580,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test @Presubmit public void testGetOrientation() { + mDisplayContent.setIgnoreOrientationRequest(false); // ActivityBuilder will resume top activities and cause the activity been added into // opening apps list. Since this test is focus on the effect of visible on getting // orientation, we skip app transition to avoid interference. @@ -2663,8 +2672,8 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testSetOrientation_restrictedByTargetSdk() { mSetFlagsRule.enableFlags(Flags.FLAG_UNIVERSAL_RESIZABLE_BY_DEFAULT); - mDisplayContent.setIgnoreOrientationRequest(true); makeDisplayLargeScreen(mDisplayContent); + assertTrue(mDisplayContent.getIgnoreOrientationRequest()); assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_SOCIAL, false); assertSetOrientation(Build.VERSION_CODES.CUR_DEVELOPMENT, CATEGORY_GAME, true); @@ -2702,6 +2711,7 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testRespectTopFullscreenOrientation() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final Configuration displayConfig = activity.mDisplayContent.getConfiguration(); final Configuration activityConfig = activity.getConfiguration(); 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/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index e0b29c937381..1cb1e3cae413 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -511,6 +511,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { @Test public void testSupportsMultiWindow_nonResizable() { final ActivityRecord activity = new ActivityBuilder(mAtm) + .setComponent(getUniqueComponentName(mContext.getPackageName())) .setCreateTask(true) .setResizeMode(RESIZE_MODE_UNRESIZEABLE) .build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index 40da9ea2d718..579ed6659976 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -365,8 +365,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue(outPrevActivities.isEmpty()); assertTrue(predictable); // reset - tf1.setAdjacentTaskFragment(null); - tf2.setAdjacentTaskFragment(null); + tf1.clearAdjacentTaskFragments(); + tf2.clearAdjacentTaskFragments(); tf1.setCompanionTaskFragment(null); tf2.setCompanionTaskFragment(null); @@ -398,8 +398,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue(predictable); // reset outPrevActivities.clear(); - tf2.setAdjacentTaskFragment(null); - tf3.setAdjacentTaskFragment(null); + tf2.clearAdjacentTaskFragments(); + tf3.clearAdjacentTaskFragments(); final TaskFragment tf4 = createTaskFragmentWithActivity(task); // Stacked + next companion to top => predict for previous activity below companion. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java index 87dbca51e24e..060b379c1281 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java @@ -84,6 +84,7 @@ public class DisplayAreaGroupTest extends WindowTestsBase { @Test public void testGetRequestedOrientationForDisplay() { + mDisplayContent.setIgnoreOrientationRequest(false); final Task task = new TaskBuilder(mSupervisor) .setTaskDisplayArea(mTaskDisplayArea).setCreateActivity(true).build(); final ActivityRecord activity = task.getTopNonFinishingActivity(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index 7b2cd63b4afb..0a7df5a305bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -491,6 +491,7 @@ public class DisplayAreaTest extends WindowTestsBase { @Test public void testSetIgnoreOrientationRequest_callSuperOnDescendantOrientationChangedNoSensor() { final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea(); + mDisplayContent.setIgnoreOrientationRequest(false); final Task stack = new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build(); final ActivityRecord activity = stack.getTopNonFinishingActivity(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 9cbea2e2f0ad..db71f2bf039d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -898,6 +898,7 @@ public class DisplayContentTests extends WindowTestsBase { public void testOrientationDefinedByKeyguard() { final DisplayContent dc = mDisplayContent; dc.getDisplayPolicy().setAwake(true); + dc.setIgnoreOrientationRequest(false); // Create a window that requests landscape orientation. It will define device orientation // by default. @@ -925,6 +926,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testOrientationForAspectRatio() { final DisplayContent dc = createNewDisplay(); + dc.setIgnoreOrientationRequest(false); // When display content is created its configuration is not yet initialized, which could // cause unnecessary configuration propagation, so initialize it here. @@ -1034,6 +1036,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testAllowsTopmostFullscreenOrientation() { final DisplayContent dc = createNewDisplay(); + dc.setIgnoreOrientationRequest(false); assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, dc.getOrientation()); dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); @@ -1112,6 +1115,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testOnDescendantOrientationRequestChanged() { final DisplayContent dc = createNewDisplay(); + dc.setIgnoreOrientationRequest(false); dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_DISABLED); dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN); @@ -1130,6 +1134,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() { final DisplayContent dc = createNewDisplay(); + dc.setIgnoreOrientationRequest(false); dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); dc.getDisplayRotation().setUserRotation( @@ -1152,6 +1157,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testOrientationBehind() { assertNull(mDisplayContent.getLastOrientationSource()); + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true) .setScreenOrientation(getRotatedOrientation(mDisplayContent)).build(); prev.setVisibleRequested(false); @@ -1172,6 +1178,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testFixedToUserRotationChanged() { final DisplayContent dc = createNewDisplay(); + dc.setIgnoreOrientationRequest(false); dc.getDisplayRotation().setFixedToUserRotation( IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); dc.getDisplayRotation().setUserRotation( @@ -1589,6 +1596,7 @@ public class DisplayContentTests extends WindowTestsBase { W_INPUT_METHOD, W_NOTIFICATION_SHADE }) @Test public void testApplyTopFixedRotationTransform() { + mDisplayContent.setIgnoreOrientationRequest(false); final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); spyOn(displayPolicy); // Only non-movable (gesture) navigation bar will be animated by fixed rotation animation. @@ -1742,6 +1750,7 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testFixedRotationWithPip() { final DisplayContent displayContent = mDefaultDisplay; + displayContent.setIgnoreOrientationRequest(false); unblockDisplayRotation(displayContent); // Unblock the condition in PinnedTaskController#continueOrientationChangeIfNeeded. doNothing().when(displayContent).prepareAppTransition(anyInt()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java index 63973345b5fb..6527af1ec704 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationImmersiveAppCompatPolicyTests.java @@ -77,7 +77,7 @@ public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBas when(mMockActivityRecord.findMainWindow()).thenReturn(mMockWindowState); doReturn(mMockActivityRecord).when(mDisplayContent).topRunningActivity(); - when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(true); + mDisplayContent.setIgnoreOrientationRequest(true); mMockAppCompatConfiguration = mock(AppCompatConfiguration.class); when(mMockAppCompatConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled()) @@ -195,7 +195,7 @@ public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBas @Test public void testIsRotationLockEnforced_ignoreOrientationRequestDisabled_lockNotEnforced() { - when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(false); + mDisplayContent.setIgnoreOrientationRequest(false); assertIsRotationLockEnforcedReturnsFalseForAllRotations(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java index 708d6860abc2..bd15bc42e811 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java @@ -106,6 +106,8 @@ public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase { // Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait). mDisplay = new DualDisplayContent.Builder(mAtm, 1920, 1200).build(); + // The test verifies that the display area can affect display's getLastOrientation(). + mDisplay.setIgnoreOrientationRequest(false); mFirstRoot = mDisplay.mFirstRoot; mSecondRoot = mDisplay.mSecondRoot; mFirstTda = mDisplay.getTaskDisplayArea(FEATURE_FIRST_TASK_CONTAINER); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index aa992504f9a5..25b9f4b8035b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -717,13 +717,13 @@ public class RecentTasksTest extends WindowTestsBase { } @Test - @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents() { testVisibleTasks_excludedFromRecents_internal(); } @Test - @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents_withRefactorFlag() { testVisibleTasks_excludedFromRecents_internal(); } @@ -767,13 +767,13 @@ public class RecentTasksTest extends WindowTestsBase { @Test @Ignore("b/342627272") - @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask() { testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal(); } @Test - @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_withRefactorFlag() { testVisibleTasks_excludedFromRecents_visibleTaskNotFirstTask_internal(); } @@ -816,13 +816,13 @@ public class RecentTasksTest extends WindowTestsBase { } @Test - @DisableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @DisableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() { testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal(); } @Test - @EnableFlags(Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL) + @EnableFlags(Flags.FLAG_ENABLE_USE_TOP_VISIBLE_ACTIVITY_FOR_EXCLUDE_FROM_RECENT_TASK) public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible_withRefactorFlag() { testVisibleTasks_excludedFromRecents_firstTaskNotVisible_internal(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java index 7cb62c5a6769..d96512588c7c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java @@ -132,6 +132,7 @@ public class RootTaskTests extends WindowTestsBase { @Test public void testClosingAppDifferentTaskOrientation() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity1 = createActivityRecord(mDisplayContent); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -146,6 +147,7 @@ public class RootTaskTests extends WindowTestsBase { @Test public void testMoveTaskToBackDifferentTaskOrientation() { + mDisplayContent.setIgnoreOrientationRequest(false); final ActivityRecord activity1 = createActivityRecord(mDisplayContent); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 7e8bd38fb6a9..699ed0263756 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -41,6 +41,7 @@ import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -63,6 +64,7 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import android.app.ActivityOptions; import android.app.WindowConfiguration; @@ -77,12 +79,14 @@ import android.graphics.Rect; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.util.Pair; import androidx.test.filters.MediumTest; import com.android.internal.app.ResolverActivity; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -693,6 +697,7 @@ public class RootWindowContainerTests extends WindowTestsBase { @Test public void testAwakeFromSleepingWithAppConfiguration() { final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); + display.setIgnoreOrientationRequest(false); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity.moveFocusableActivityToTop("test"); assertTrue(activity.getRootTask().isFocusedRootTaskOnDisplay()); @@ -1331,6 +1336,38 @@ public class RootWindowContainerTests extends WindowTestsBase { assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask()); } + @EnableFlags(Flags.FLAG_ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING) + @Test + public void testSwitchUser_withVisibleRootTasks_storesAllVisibleRootTasksForCurrentUser() { + // Set up root tasks + final Task rootTask1 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final Task rootTask2 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final Task rootTask3 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( + WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); + doReturn(rootTask3).when(mRootWindowContainer).getTopDisplayFocusedRootTask(); + + // Set up user ids and visibility + rootTask1.mUserId = mRootWindowContainer.mCurrentUser; + rootTask2.mUserId = mRootWindowContainer.mCurrentUser; + rootTask3.mUserId = mRootWindowContainer.mCurrentUser; + rootTask1.mVisibleRequested = false; + rootTask2.mVisibleRequested = true; + rootTask3.mVisibleRequested = true; + + // Switch to a different user + int currentUser = mRootWindowContainer.mCurrentUser; + int otherUser = currentUser + 1; + mRootWindowContainer.switchUser(otherUser, null); + + // Verify that the previous user persists it's previous visible root tasks + assertArrayEquals( + new int[]{rootTask2.mTaskId, rootTask3.mTaskId}, + mRootWindowContainer.mUserVisibleRootTasks.get(currentUser).toArray() + ); + } + @Test public void testLockAllProfileTasks() { final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID; diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index bf96f0eb03b8..201ff51f1495 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -107,6 +107,8 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; +import android.view.DisplayCutout; +import android.view.DisplayInfo; import android.view.InsetsFrameProvider; import android.view.InsetsSource; import android.view.InsetsState; @@ -210,6 +212,37 @@ public class SizeCompatTests extends WindowTestsBase { return setUpApp(builder.build(), appBuilder); } + private void setUpLargeScreenDisplayWithApp(int dw, int dh) { + final DisplayContent display = mDisplayContent; + final DisplayInfo displayInfo = display.getDisplayInfo(); + displayInfo.logicalWidth = dw; + displayInfo.logicalHeight = dh; + // Prevent legacy sdk from being affected by INSETS_DECOUPLED_CONFIGURATION_ENFORCED. + display.mInitialDisplayCutout = displayInfo.displayCutout = DisplayCutout.NO_CUTOUT; + // Smallest screen width=747dp according to 1400/(300/160). + display.mBaseDisplayDensity = displayInfo.logicalDensityDpi = + TestDisplayContent.DEFAULT_LOGICAL_DISPLAY_DENSITY; + doNothing().when(display).updateDisplayInfo(any()); + resizeDisplay(display, displayInfo.logicalWidth, displayInfo.logicalHeight); + assertTrue(display.isLargeScreen()); + if (com.android.window.flags.Flags.universalResizableByDefault()) { + assertTrue("Large screen must ignore orientation request", + display.getIgnoreOrientationRequest()); + } else { + display.setIgnoreOrientationRequest(true); + } + setUpApp(display, null /* appBuilder */); + spyOn(display.getDisplayRotation()); + } + + private void setUpLandscapeLargeScreenDisplayWithApp() { + setUpLargeScreenDisplayWithApp(/* dw */ 2800, /* dh */ 1400); + } + + private void setUpPortraitLargeScreenDisplayWithApp() { + setUpLargeScreenDisplayWithApp(/* dw */ 1400, /* dh */ 2800); + } + @Test public void testHorizontalReachabilityEnabledForTranslucentActivities() { testReachabilityEnabledForTranslucentActivity(/* dw */ 2500, /* dh */1000, @@ -658,9 +691,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testIsLetterboxed_activityFromBubble_returnsFalse() { - setUpDisplaySizeWithApp(1000, 2500); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - spyOn(mActivity); + setUpPortraitLargeScreenDisplayWithApp(); doReturn(true).when(mActivity).getLaunchedFromBubble(); prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); @@ -1694,10 +1725,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testGetLetterboxInnerBounds_noScalingApplied() { // Set up a display in portrait and ignoring orientation request. - final int dw = 1400; - final int dh = 2800; - setUpDisplaySizeWithApp(dw, dh); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpPortraitLargeScreenDisplayWithApp(); + final int dw = mDisplayContent.mBaseDisplayWidth; + final int dh = mDisplayContent.mBaseDisplayHeight; // Rotate display to landscape. rotateDisplay(mActivity.mDisplayContent, ROTATION_90); @@ -1823,8 +1853,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedLetterbox() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT); @@ -1852,8 +1881,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMinAspectRatio() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed // orientation letterbox. @@ -1884,8 +1912,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMaxAspectRatio() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app with max aspect ratio lower that aspect ratio override for fixed // orientation letterbox. @@ -1915,8 +1942,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_fixedOrientationAppWithAspectRatioOverride() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); final float fixedOrientationLetterboxAspectRatio = 1.1f; mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio( @@ -2011,8 +2037,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); final float fixedOrientationLetterboxAspectRatio = 1.1f; mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio( @@ -2045,13 +2070,10 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testComputeConfigResourceOverrides_unresizableApp() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); - final Rect activityBounds = new Rect(mActivity.getBounds()); - int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp; int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp; @@ -2068,7 +2090,7 @@ public class SizeCompatTests extends WindowTestsBase { // After we rotate, the activity should go in the size-compat mode and report the same // configuration values. - assertDownScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp); assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp); assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp); @@ -2087,14 +2109,11 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app without max aspect. prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */); - final Rect activityBounds = new Rect(mActivity.getBounds()); - int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp; int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp; @@ -2206,10 +2225,10 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testSystemFullscreenOverrideForLandscapeDisplay() { - final int displayWidth = 1600; - final int displayHeight = 1400; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; + spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()); doReturn(true).when( mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()) @@ -2226,10 +2245,10 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testSystemFullscreenOverrideForPortraitDisplay() { - final int displayWidth = 1400; - final int displayHeight = 1600; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpPortraitLargeScreenDisplayWithApp(); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; + spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()); doReturn(true).when( mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()) @@ -2619,7 +2638,7 @@ public class SizeCompatTests extends WindowTestsBase { @EnableCompatChanges({ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION}) public void testOverrideRespectRequestedOrientationIsEnabled_orientationIsRespected() { // Set up a display in landscape - setUpDisplaySizeWithApp(2800, 1400); + setUpDisplaySizeWithApp(1000, 500); final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */ false, RESIZE_MODE_UNRESIZEABLE, SCREEN_ORIENTATION_PORTRAIT); @@ -2636,7 +2655,7 @@ public class SizeCompatTests extends WindowTestsBase { @EnableCompatChanges({ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION}) public void testOverrideRespectRequestedOrientationIsEnabled_multiWindow_orientationIgnored() { // Set up a display in landscape - setUpDisplaySizeWithApp(2800, 1400); + setUpDisplaySizeWithApp(1000, 500); final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */ false, RESIZE_MODE_UNRESIZEABLE, SCREEN_ORIENTATION_PORTRAIT); @@ -2655,10 +2674,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testSplitAspectRatioForUnresizableLandscapeApps() { // Set up a display in portrait and ignoring orientation request. - int screenWidth = 1400; - int screenHeight = 1600; - setUpDisplaySizeWithApp(screenWidth, screenHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLargeScreenDisplayWithApp(1400, 2400); + final int screenWidth = mDisplayContent.mBaseDisplayWidth; + final int screenHeight = mDisplayContent.mBaseDisplayHeight; mActivity.mWmService.mAppCompatConfiguration .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true); @@ -2692,10 +2710,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayAspectRatioForResizablePortraitApps() { // Set up a display in portrait and ignoring orientation request. - int displayWidth = 1400; - int displayHeight = 1600; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLargeScreenDisplayWithApp(1400, 2400); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; mWm.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(2f); // Enable display aspect ratio to take precedence before @@ -2728,10 +2745,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayAspectRatioForResizableLandscapeApps() { // Set up a display in landscape and ignoring orientation request. - int displayWidth = 1600; - int displayHeight = 1400; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; mWm.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(2f); // Enable display aspect ratio to take precedence before @@ -2764,10 +2780,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayAspectRatioForUnresizableLandscapeApps() { // Set up a display in portrait and ignoring orientation request. - int displayWidth = 1400; - int displayHeight = 1600; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpPortraitLargeScreenDisplayWithApp(); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); // Enable display aspect ratio to take precedence before @@ -2791,10 +2806,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayAspectRatioForUnresizablePortraitApps() { // Set up a display in landscape and ignoring orientation request. - int displayWidth = 1600; - int displayHeight = 1400; - setUpDisplaySizeWithApp(displayWidth, displayHeight); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); + final int displayWidth = mDisplayContent.mBaseDisplayWidth; + final int displayHeight = mDisplayContent.mBaseDisplayHeight; mActivity.mWmService.mAppCompatConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); // Enable display aspect ratio to take precedence before @@ -2819,8 +2833,7 @@ public class SizeCompatTests extends WindowTestsBase { public void testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -2837,7 +2850,7 @@ public class SizeCompatTests extends WindowTestsBase { // App should be in size compat. assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); - assertDownScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); assertEquals(activityBounds.width(), newActivityBounds.width()); assertEquals(activityBounds.height(), newActivityBounds.height()); assertActivityMaxBoundsSandboxed(); @@ -2846,8 +2859,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_sizeCompatAfterRotate() { // Set up a display in portrait and ignoring orientation request. - setUpDisplaySizeWithApp(1400, 2800); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpPortraitLargeScreenDisplayWithApp(); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -2882,9 +2894,8 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInLetterbox() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); + setUpLandscapeLargeScreenDisplayWithApp(); final DisplayContent display = mActivity.mDisplayContent; - display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -2928,9 +2939,7 @@ public class SizeCompatTests extends WindowTestsBase { @EnableCompatChanges({ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION}) public void testDisplayIgnoreOrientationRequest_orientationChangedToUnspecified() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - final DisplayContent display = mActivity.mDisplayContent; - display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -2950,9 +2959,8 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_newLaunchedMaxAspectApp() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); + setUpLandscapeLargeScreenDisplayWithApp(); final DisplayContent display = mActivity.mDisplayContent; - display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app without max aspect. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -3001,9 +3009,7 @@ public class SizeCompatTests extends WindowTestsBase { @SuppressWarnings("GuardedBy") public void testDisplayIgnoreOrientationRequest_pausedAppNotLostSizeCompat() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - final DisplayContent display = mActivity.mDisplayContent; - display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); // Portrait fixed app. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -3019,7 +3025,6 @@ public class SizeCompatTests extends WindowTestsBase { // App should be in size compat. assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); - assertDownScaled(); assertThat(mActivity.inSizeCompatMode()).isTrue(); // Activity max bounds are sandboxed due to size compat mode. assertActivityMaxBoundsSandboxed(); @@ -3035,7 +3040,7 @@ public class SizeCompatTests extends WindowTestsBase { verify(scmPolicy, never()).clearSizeCompatMode(); assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); - assertDownScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); assertEquals(activityBounds, mActivity.getBounds()); // Activity max bounds are sandboxed due to size compat. assertActivityMaxBoundsSandboxed(); @@ -3044,9 +3049,8 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testDisplayIgnoreOrientationRequest_rotated180_notInSizeCompat() { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); + setUpLandscapeLargeScreenDisplayWithApp(); final DisplayContent display = mActivity.mDisplayContent; - display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); // Portrait fixed app. prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); @@ -3063,7 +3067,7 @@ public class SizeCompatTests extends WindowTestsBase { // App should be in size compat. assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioPolicy() .isLetterboxedForFixedOrientationAndAspectRatio()); - assertDownScaled(); + assertThat(mActivity.inSizeCompatMode()).isTrue(); assertActivityMaxBoundsSandboxed(); // Rotate display to landscape. @@ -3246,8 +3250,9 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testTaskDisplayAreaNotFillDisplay() { - setUpDisplaySizeWithApp(1400, 2800); + setUpPortraitLargeScreenDisplayWithApp(); final DisplayContent display = mActivity.mDisplayContent; + display.setIgnoreOrientationRequest(false); final TaskDisplayArea taskDisplayArea = mActivity.getDisplayArea(); taskDisplayArea.setBounds(0, 0, 1000, 2400); @@ -3430,8 +3435,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testIsHorizontalReachabilityEnabled_splitScreen_false() { mAtm.mDevEnableNonResizableMultiWindow = true; - setUpDisplaySizeWithApp(2800, 1000); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mWm.mAppCompatConfiguration.setIsHorizontalReachabilityEnabled(true); setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true); final TestSplitOrganizer organizer = @@ -3518,8 +3522,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testIsHorizontalReachabilityEnabled_emptyBounds_true() { - setUpDisplaySizeWithApp(/* dw */ 2800, /* dh */ 1000); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mWm.mAppCompatConfiguration.setIsHorizontalReachabilityEnabled(true); setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true); @@ -3566,8 +3569,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() { - setUpDisplaySizeWithApp(2800, 1000); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mWm.mAppCompatConfiguration.setIsHorizontalReachabilityEnabled(true); setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ true); @@ -3787,12 +3789,10 @@ public class SizeCompatTests extends WindowTestsBase { } private void assertLandscapeActivityAlignedToBottomWithNavbar(boolean immersive) { - final int screenHeight = 2800; - final int screenWidth = 1400; + setUpPortraitLargeScreenDisplayWithApp(); + final int screenHeight = mDisplayContent.mBaseDisplayHeight; + final int screenWidth = mDisplayContent.mBaseDisplayWidth; final int taskbarHeight = 200; - setUpDisplaySizeWithApp(screenWidth, screenHeight); - - mActivity.mDisplayContent.setIgnoreOrientationRequest(true); mActivity.mWmService.mAppCompatConfiguration.setLetterboxVerticalPositionMultiplier(1.0f); final InsetsSource navSource = new InsetsSource( @@ -3972,8 +3972,7 @@ public class SizeCompatTests extends WindowTestsBase { float letterboxHorizontalPositionMultiplier, Rect fixedOrientationLetterbox, Rect sizeCompatUnscaled, Rect sizeCompatScaled) { // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mActivity.mWmService.mAppCompatConfiguration.setLetterboxHorizontalPositionMultiplier( letterboxHorizontalPositionMultiplier); @@ -4177,13 +4176,28 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() { + // Set up a display in landscape and ignoring orientation request. + setUpLandscapeLargeScreenDisplayWithApp(); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + + final Consumer<Float> assertHorizontalPosition = letterboxHorizontalPositionMultiplier -> { + mActivity.mWmService.mAppCompatConfiguration.setLetterboxHorizontalPositionMultiplier( + letterboxHorizontalPositionMultiplier); + mActivity.recomputeConfiguration(); + assertFitted(); + // Rotate to put activity in size compat mode. + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + assertTrue(mActivity.inSizeCompatMode()); + // Activity is in size compat mode but not scaled. + assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds()); + if (letterboxHorizontalPositionMultiplier < 1f) { + rotateDisplay(mActivity.mDisplayContent, ROTATION_0); + } + }; // When activity width equals parent width, multiplier shouldn't have any effect. - assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( - /* letterboxHorizontalPositionMultiplier */ 0.0f); - assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( - /* letterboxHorizontalPositionMultiplier */ 0.5f); - assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( - /* letterboxHorizontalPositionMultiplier */ 1.0f); + assertHorizontalPosition.accept(0.0f); + assertHorizontalPosition.accept(0.5f); + assertHorizontalPosition.accept(1.0f); } @Test @@ -4354,8 +4368,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testUpdateResolvedBoundsHorizontalPosition_bookModeEnabled() { // Set up a display in landscape with a fixed-orientation PORTRAIT app - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mWm.mAppCompatConfiguration.setIsAutomaticReachabilityInBookModeEnabled(true); mWm.mAppCompatConfiguration.setLetterboxHorizontalPositionMultiplier( 1.0f /*letterboxHorizontalPositionMultiplier*/); @@ -4380,8 +4393,7 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testUpdateResolvedBoundsHorizontalPosition_bookModeDisabled_centered() { // Set up a display in landscape with a fixed-orientation PORTRAIT app - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpLandscapeLargeScreenDisplayWithApp(); mWm.mAppCompatConfiguration.setIsAutomaticReachabilityInBookModeEnabled(false); mWm.mAppCompatConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f); prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT); @@ -4462,8 +4474,7 @@ public class SizeCompatTests extends WindowTestsBase { float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox, Rect sizeCompatUnscaled, Rect sizeCompatScaled) { // Set up a display in portrait and ignoring orientation request. - setUpDisplaySizeWithApp(1400, 2800); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + setUpPortraitLargeScreenDisplayWithApp(); mActivity.mWmService.mAppCompatConfiguration.setLetterboxVerticalPositionMultiplier( letterboxVerticalPositionMultiplier); @@ -5036,23 +5047,6 @@ public class SizeCompatTests extends WindowTestsBase { return (dimensionToSplit - (dividerWindowWidth - dividerInsets * 2)) / 2; } - private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( - float letterboxHorizontalPositionMultiplier) { - // Set up a display in landscape and ignoring orientation request. - setUpDisplaySizeWithApp(2800, 1400); - mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - - mActivity.mWmService.mAppCompatConfiguration.setLetterboxHorizontalPositionMultiplier( - letterboxHorizontalPositionMultiplier); - prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); - assertFitted(); - // Rotate to put activity in size compat mode. - rotateDisplay(mActivity.mDisplayContent, ROTATION_90); - assertTrue(mActivity.inSizeCompatMode()); - // Activity is in size compat mode but not scaled. - assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds()); - } - private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity( float letterboxVerticalPositionMultiplier) { // Set up a display in portrait and ignoring orientation request. diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 08622e68629a..921228ff2a5b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -78,6 +78,8 @@ import android.view.SurfaceControl; import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.internal.os.BackgroundThread; +import com.android.internal.protolog.ProtoLog; +import com.android.internal.protolog.WmProtoLogGroups; import com.android.server.AnimationThread; import com.android.server.DisplayThread; import com.android.server.LocalServices; @@ -183,6 +185,8 @@ public class SystemServicesTestRule implements TestRule { } private void setUp() { + ProtoLog.init(WmProtoLogGroups.values()); + if (mOnBeforeServicesCreated != null) { mOnBeforeServicesCreated.run(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 65a6a69fc45e..dafa96f91812 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -51,6 +51,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.clearInvocations; @@ -62,6 +63,7 @@ import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Rect; import android.os.Binder; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; import android.view.View; @@ -1066,6 +1068,98 @@ public class TaskFragmentTest extends WindowTestsBase { Math.min(outConfig.screenWidthDp, outConfig.screenHeightDp)); } + @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS) + @Test + public void testSetAdjacentTaskFragments() { + final Task task = createTask(mDisplayContent); + final TaskFragment tf0 = createTaskFragmentWithActivity(task); + final TaskFragment tf1 = createTaskFragmentWithActivity(task); + final TaskFragment tf2 = createTaskFragmentWithActivity(task); + final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2); + assertFalse(tf0.hasAdjacentTaskFragment()); + + tf0.setAdjacentTaskFragments(adjacentTfs); + + assertSame(adjacentTfs, tf0.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf1.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf2.getAdjacentTaskFragments()); + assertTrue(tf0.hasAdjacentTaskFragment()); + assertTrue(tf1.hasAdjacentTaskFragment()); + assertTrue(tf2.hasAdjacentTaskFragment()); + + final TaskFragment.AdjacentSet adjacentTfs2 = new TaskFragment.AdjacentSet(tf0, tf1); + tf0.setAdjacentTaskFragments(adjacentTfs2); + + assertSame(adjacentTfs2, tf0.getAdjacentTaskFragments()); + assertSame(adjacentTfs2, tf1.getAdjacentTaskFragments()); + assertNull(tf2.getAdjacentTaskFragments()); + assertTrue(tf0.hasAdjacentTaskFragment()); + assertTrue(tf1.hasAdjacentTaskFragment()); + assertFalse(tf2.hasAdjacentTaskFragment()); + } + + @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS) + @Test + public void testClearAdjacentTaskFragments() { + final Task task = createTask(mDisplayContent); + final TaskFragment tf0 = createTaskFragmentWithActivity(task); + final TaskFragment tf1 = createTaskFragmentWithActivity(task); + final TaskFragment tf2 = createTaskFragmentWithActivity(task); + final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2); + tf0.setAdjacentTaskFragments(adjacentTfs); + + tf0.clearAdjacentTaskFragments(); + + assertNull(tf0.getAdjacentTaskFragments()); + assertNull(tf1.getAdjacentTaskFragments()); + assertNull(tf2.getAdjacentTaskFragments()); + assertFalse(tf0.hasAdjacentTaskFragment()); + assertFalse(tf1.hasAdjacentTaskFragment()); + assertFalse(tf2.hasAdjacentTaskFragment()); + } + + @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS) + @Test + public void testRemoveFromAdjacentTaskFragments() { + final Task task = createTask(mDisplayContent); + final TaskFragment tf0 = createTaskFragmentWithActivity(task); + final TaskFragment tf1 = createTaskFragmentWithActivity(task); + final TaskFragment tf2 = createTaskFragmentWithActivity(task); + final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2); + tf0.setAdjacentTaskFragments(adjacentTfs); + + tf0.removeFromAdjacentTaskFragments(); + + assertNull(tf0.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf1.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf2.getAdjacentTaskFragments()); + assertFalse(adjacentTfs.contains(tf0)); + assertTrue(tf1.isAdjacentTo(tf2)); + assertTrue(tf2.isAdjacentTo(tf1)); + assertFalse(tf1.isAdjacentTo(tf0)); + assertFalse(tf0.isAdjacentTo(tf1)); + assertFalse(tf0.isAdjacentTo(tf0)); + assertFalse(tf1.isAdjacentTo(tf1)); + } + + @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS) + @Test + public void testRemoveFromAdjacentTaskFragmentsWhenRemove() { + final Task task = createTask(mDisplayContent); + final TaskFragment tf0 = createTaskFragmentWithActivity(task); + final TaskFragment tf1 = createTaskFragmentWithActivity(task); + final TaskFragment tf2 = createTaskFragmentWithActivity(task); + final TaskFragment.AdjacentSet adjacentTfs = new TaskFragment.AdjacentSet(tf0, tf1, tf2); + tf0.setAdjacentTaskFragments(adjacentTfs); + + tf0.removeImmediately(); + + assertNull(tf0.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf1.getAdjacentTaskFragments()); + assertSame(adjacentTfs, tf2.getAdjacentTaskFragments()); + assertFalse(adjacentTfs.contains(tf0)); + } + private WindowState createAppWindow(ActivityRecord app, String name) { final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, app, name, 0 /* ownerId */, false /* ownerCanAddInternalSystemWindow */, new TestIWindow()); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index e4512c31069a..1febc9fb4742 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -527,6 +527,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testHandlesOrientationChangeFromDescendant() { + mDisplayContent.setIgnoreOrientationRequest(false); final Task rootTask = createTask(mDisplayContent, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); final Task leafTask1 = createTaskInRootTask(rootTask, 0 /* userId */); @@ -1570,6 +1571,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testNotSpecifyOrientationByFloatingTask() { + mDisplayContent.setIgnoreOrientationRequest(false); final Task task = new TaskBuilder(mSupervisor) .setCreateActivity(true).setCreateParentTask(true).build(); final ActivityRecord activity = task.getTopMostActivity(); @@ -1589,6 +1591,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testNotSpecifyOrientation_taskDisplayAreaNotFocused() { + mDisplayContent.setIgnoreOrientationRequest(false); final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea( mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea", @@ -1625,6 +1628,7 @@ public class TaskTests extends WindowTestsBase { @Test public void testTaskOrientationOnDisplayWindowingModeChange() { + mDisplayContent.setIgnoreOrientationRequest(false); // Skip unnecessary operations to speed up the test. mAtm.deferWindowLayout(); final Task task = getTestTask(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 039a3ddd3e4f..78f32c1a4f88 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -1333,6 +1333,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testDeferRotationForTransientLaunch() { + mDisplayContent.setIgnoreOrientationRequest(false); final TestTransitionPlayer player = registerTestTransitionPlayer(); assumeFalse(mDisplayContent.mTransitionController.useShellTransitionsRotation()); final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java index 42752c326615..f1180ff93edb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransparentPolicyTest.java @@ -314,6 +314,7 @@ public class TransparentPolicyTest extends WindowTestsBase { runTestScenario((robot) -> { robot.transparentActivity((ta) -> { ta.applyOnActivity((a) -> { + a.setIgnoreOrientationRequest(false); a.applyToTopActivity((topActivity) -> { topActivity.mWmService.mAppCompatConfiguration .setLetterboxHorizontalPositionMultiplier(1.0f); 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/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 410fa2879600..da4c522834a6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -777,6 +777,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSetIgnoreOrientationRequest_taskDisplayArea() { removeGlobalMinSizeRestriction(); + mDisplayContent.setIgnoreOrientationRequest(false); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); final Task rootTask = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); @@ -815,6 +816,7 @@ public class WindowOrganizerTests extends WindowTestsBase { @Test public void testSetIgnoreOrientationRequest_displayContent() { removeGlobalMinSizeRestriction(); + mDisplayContent.setIgnoreOrientationRequest(false); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); final Task rootTask = taskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); @@ -924,6 +926,49 @@ public class WindowOrganizerTests extends WindowTestsBase { assertEquals(dc.getDefaultTaskDisplayArea().mLaunchAdjacentFlagRootTask, null); } + @EnableFlags(Flags.FLAG_ALLOW_MULTIPLE_ADJACENT_TASK_FRAGMENTS) + @Test + public void testSetAdjacentLaunchRootSet() { + final DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY); + + final Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + dc, WINDOWING_MODE_MULTI_WINDOW, null); + final RunningTaskInfo info1 = task1.getTaskInfo(); + final Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + dc, WINDOWING_MODE_MULTI_WINDOW, null); + final RunningTaskInfo info2 = task2.getTaskInfo(); + final Task task3 = mWm.mAtmService.mTaskOrganizerController.createRootTask( + dc, WINDOWING_MODE_MULTI_WINDOW, null); + final RunningTaskInfo info3 = task3.getTaskInfo(); + + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.setAdjacentRootSet(info1.token, info2.token, info3.token); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + assertTrue(task1.hasAdjacentTaskFragment()); + assertTrue(task2.hasAdjacentTaskFragment()); + assertTrue(task3.hasAdjacentTaskFragment()); + assertTrue(task1.isAdjacentTo(task2)); + assertTrue(task1.isAdjacentTo(task3)); + assertTrue(task2.isAdjacentTo(task3)); + + wct = new WindowContainerTransaction(); + wct.clearAdjacentRoots(info1.token); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + assertFalse(task1.hasAdjacentTaskFragment()); + assertTrue(task2.hasAdjacentTaskFragment()); + assertTrue(task3.hasAdjacentTaskFragment()); + assertFalse(task1.isAdjacentTo(task2)); + assertFalse(task1.isAdjacentTo(task3)); + assertTrue(task2.isAdjacentTo(task3)); + + wct = new WindowContainerTransaction(); + wct.clearAdjacentRoots(info2.token); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); + assertFalse(task2.hasAdjacentTaskFragment()); + assertFalse(task3.hasAdjacentTaskFragment()); + assertFalse(task2.isAdjacentTo(task3)); + } + @Test public void testTileAddRemoveChild() { final StubOrganizer listener = new StubOrganizer(); 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..b27025c34d6b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -201,14 +201,10 @@ public class WindowTestsBase extends SystemServiceTestsBase { * {@link WindowTestsBase#setUpBase()}. */ private static boolean sGlobalOverridesChecked; + /** * Whether device-specific overrides have already been checked in - * {@link WindowTestsBase#setUpBase()} when the default display is used. - */ - private static boolean sOverridesCheckedDefaultDisplay; - /** - * Whether device-specific overrides have already been checked in - * {@link WindowTestsBase#setUpBase()} when a {@link TestDisplayContent} is used. + * {@link WindowTestsBase#setUpBase()}. */ private static boolean sOverridesCheckedTestDisplay; @@ -332,17 +328,14 @@ public class WindowTestsBase extends SystemServiceTestsBase { private void checkDeviceSpecificOverridesNotApplied() { // Check global overrides if (!sGlobalOverridesChecked) { + sGlobalOverridesChecked = true; assertEquals(0, mWm.mAppCompatConfiguration.getFixedOrientationLetterboxAspectRatio(), 0 /* delta */); - sGlobalOverridesChecked = true; } // Check display-specific overrides - if (!sOverridesCheckedDefaultDisplay && mDisplayContent == mDefaultDisplay) { - assertFalse(mDisplayContent.getIgnoreOrientationRequest()); - sOverridesCheckedDefaultDisplay = true; - } else if (!sOverridesCheckedTestDisplay && mDisplayContent instanceof TestDisplayContent) { - assertFalse(mDisplayContent.getIgnoreOrientationRequest()); + if (!sOverridesCheckedTestDisplay) { sOverridesCheckedTestDisplay = true; + assertFalse(mDisplayContent.mHasSetIgnoreOrientationRequest); } } @@ -1121,7 +1114,7 @@ public class WindowTestsBase extends SystemServiceTestsBase { displayContent.getDisplayRotation().configure(width, height); final Configuration c = new Configuration(); displayContent.computeScreenConfiguration(c); - displayContent.onRequestedOverrideConfigurationChanged(c); + displayContent.performDisplayOverrideConfigUpdate(c); } static void makeDisplayLargeScreen(DisplayContent displayContent) { @@ -2039,9 +2032,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/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..4cb622b3eb9e 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; @@ -99,20 +105,30 @@ public final class CellIdentityCdma extends CellIdentity { */ public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, @Nullable String alphal, @Nullable String alphas) { - super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas); - mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX); - mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX); - mBasestationId = inRangeOrUnavailable(bid, 0, BASESTATION_ID_MAX); - lat = inRangeOrUnavailable(lat, LATITUDE_MIN, LATITUDE_MAX); - lon = inRangeOrUnavailable(lon, LONGITUDE_MIN, LONGITUDE_MAX); - - if (!isNullIsland(lat, lon)) { - mLongitude = lon; - mLatitude = lat; + super(TAG, CellInfo.TYPE_CDMA, null, null, Flags.cleanupCdma() ? null : alphal, + Flags.cleanupCdma() ? null : alphas); + if (Flags.cleanupCdma()) { + mNetworkId = CellInfo.UNAVAILABLE; + mSystemId = CellInfo.UNAVAILABLE; + mBasestationId = CellInfo.UNAVAILABLE; + mLongitude = CellInfo.UNAVAILABLE; + mLatitude = CellInfo.UNAVAILABLE; + mGlobalCellId = null; } else { - mLongitude = mLatitude = CellInfo.UNAVAILABLE; + mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX); + mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX); + mBasestationId = inRangeOrUnavailable(bid, 0, BASESTATION_ID_MAX); + lat = inRangeOrUnavailable(lat, LATITUDE_MIN, LATITUDE_MAX); + lon = inRangeOrUnavailable(lon, LONGITUDE_MIN, LONGITUDE_MAX); + + if (!isNullIsland(lat, lon)) { + mLongitude = lon; + mLatitude = lat; + } else { + mLongitude = mLatitude = CellInfo.UNAVAILABLE; + } + updateGlobalCellId(); } - updateGlobalCellId(); } private CellIdentityCdma(@NonNull CellIdentityCdma cid) { @@ -124,7 +140,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 +177,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 +189,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 +201,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 +215,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 +230,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 +245,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() { @@ -267,17 +310,43 @@ public final class CellIdentityCdma extends CellIdentity { /** Construct from Parcel, type has already been processed */ private CellIdentityCdma(Parcel in) { super(TAG, CellInfo.TYPE_CDMA, in); - mNetworkId = in.readInt(); - mSystemId = in.readInt(); - mBasestationId = in.readInt(); - mLongitude = in.readInt(); - mLatitude = in.readInt(); - - updateGlobalCellId(); - if (DBG) log(toString()); + + if (Flags.cleanupCdma()) { + in.readInt(); + mNetworkId = CellInfo.UNAVAILABLE; + + in.readInt(); + mSystemId = CellInfo.UNAVAILABLE; + + in.readInt(); + mBasestationId = CellInfo.UNAVAILABLE; + + in.readInt(); + mLongitude = CellInfo.UNAVAILABLE; + + in.readInt(); + mLatitude = CellInfo.UNAVAILABLE; + + mGlobalCellId = null; + } else { + mNetworkId = in.readInt(); + mSystemId = in.readInt(); + mBasestationId = in.readInt(); + mLongitude = in.readInt(); + mLatitude = in.readInt(); + + updateGlobalCellId(); + 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/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java index 5298e67bdf80..12a7294c42de 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -21,6 +21,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import com.android.internal.telephony.flags.Flags; import com.android.telephony.Rlog; import java.util.Objects; @@ -68,13 +69,17 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements */ public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, int evdoSnr) { - mCdmaDbm = inRangeOrUnavailable(cdmaDbm, -120, 0); - mCdmaEcio = inRangeOrUnavailable(cdmaEcio, -160, 0); - mEvdoDbm = inRangeOrUnavailable(evdoDbm, -120, 0); - mEvdoEcio = inRangeOrUnavailable(evdoEcio, -160, 0); - mEvdoSnr = inRangeOrUnavailable(evdoSnr, 0, 8); + if (Flags.cleanupCdma()) { + setDefaultValues(); + } else { + mCdmaDbm = inRangeOrUnavailable(cdmaDbm, -120, 0); + mCdmaEcio = inRangeOrUnavailable(cdmaEcio, -160, 0); + mEvdoDbm = inRangeOrUnavailable(evdoDbm, -120, 0); + mEvdoEcio = inRangeOrUnavailable(evdoEcio, -160, 0); + mEvdoSnr = inRangeOrUnavailable(evdoSnr, 0, 8); - updateLevel(null, null); + updateLevel(null, null); + } } /** @hide */ @@ -84,6 +89,10 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements /** @hide */ protected void copyFrom(CellSignalStrengthCdma s) { + if (Flags.cleanupCdma()) { + setDefaultValues(); + return; + } mCdmaDbm = s.mCdmaDbm; mCdmaEcio = s.mCdmaEcio; mEvdoDbm = s.mEvdoDbm; @@ -389,6 +398,7 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements /** @hide */ @Override public boolean isValid() { + if (Flags.cleanupCdma()) return false; return !this.equals(sInvalid); } @@ -446,7 +456,12 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements mEvdoEcio = in.readInt(); mEvdoSnr = in.readInt(); mLevel = in.readInt(); - if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString()); + + if (Flags.cleanupCdma()) { + setDefaultValues(); + } else { + if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString()); + } } /** Implement the Parcelable interface */ 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/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 65a52daae99f..24fb8c5da2d7 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,13 +2445,17 @@ 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) public String getMeid() { + if (Flags.cleanupCdma()) return null; return getMeid(getSlotIndex()); } @@ -2456,13 +2491,17 @@ 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) public String getMeid(int slotIndex) { + if (Flags.cleanupCdma()) return null; ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -2485,12 +2524,16 @@ 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() { + if (Flags.cleanupCdma()) return null; return getManufacturerCode(getSlotIndex()); } @@ -2500,12 +2543,16 @@ 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) { + if (Flags.cleanupCdma()) return null; ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -2648,7 +2695,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 +3123,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 +3163,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. @@ -6292,6 +6375,7 @@ public class TelephonyManager { * @deprecated use {@link #getImsPrivateUserIdentity()} */ @UnsupportedAppUsage + @Deprecated public String getIsimImpi() { try { IPhoneSubInfo info = getSubscriberInfoService(); @@ -6381,6 +6465,7 @@ public class TelephonyManager { * @deprecated use {@link #getImsPublicUserIdentities()} */ @UnsupportedAppUsage + @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu() { @@ -6761,9 +6846,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 +6862,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 +6904,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 +6915,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,24 +6925,31 @@ 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) public @EriIconIndex int getCdmaEnhancedRoamingIndicatorDisplayNumber() { + if (Flags.cleanupCdma()) return -1; return getCdmaEriIconIndex(getSubId()); } /** * 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) { + if (Flags.cleanupCdma()) return -1; try { ITelephony telephony = getITelephony(); if (telephony == null) @@ -6856,11 +6969,14 @@ 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) { + if (Flags.cleanupCdma()) return -1; try { ITelephony telephony = getITelephony(); if (telephony == null) @@ -6878,21 +6994,27 @@ 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() { + if (Flags.cleanupCdma()) return null; return getCdmaEriText(getSubId()); } /** * 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) { + if (Flags.cleanupCdma()) return null; try { ITelephony telephony = getITelephony(); if (telephony == null) @@ -8166,10 +8288,13 @@ 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) { + if (Flags.cleanupCdma()) return ""; try { ITelephony telephony = getITelephony(); if (telephony != null) @@ -8194,9 +8319,12 @@ 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) { + if (Flags.cleanupCdma()) return false; try { ITelephony telephony = getITelephony(); if (telephony != null) @@ -8220,9 +8348,12 @@ 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) { + if (Flags.cleanupCdma()) return false; try { ITelephony telephony = getITelephony(); if (telephony != null) @@ -8248,12 +8379,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 +8421,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 +8463,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) @@ -8355,7 +8500,9 @@ public class TelephonyManager { if (telephony == null) { throw new IllegalStateException("telephony service is null."); } - telephony.rebootModem(getSlotIndex()); + if (!telephony.rebootModem(getSlotIndex())) { + throw new RuntimeException("Couldn't reboot modem (it may be not supported)"); + } } catch (RemoteException ex) { Rlog.e(TAG, "rebootRadio RemoteException", ex); throw ex.rethrowAsRuntimeException(); @@ -9272,20 +9419,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 +9449,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 +9463,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 +9536,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 +9565,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 +9581,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 +9623,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; @@ -10533,24 +10700,32 @@ 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) public String getCdmaMdn() { + if (Flags.cleanupCdma()) return null; return getCdmaMdn(getSubId()); } /** * @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) public String getCdmaMdn(int subId) { + if (Flags.cleanupCdma()) return null; try { ITelephony telephony = getITelephony(); if (telephony == null) @@ -10566,24 +10741,32 @@ 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) public String getCdmaMin() { + if (Flags.cleanupCdma()) return null; return getCdmaMin(getSubId()); } /** * @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) public String getCdmaMin(int subId) { + if (Flags.cleanupCdma()) return null; try { ITelephony telephony = getITelephony(); if (telephony == null) @@ -11868,12 +12051,16 @@ 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) public @CdmaRoamingMode int getCdmaRoamingMode() { + if (Flags.cleanupCdma()) return CDMA_ROAMING_MODE_RADIO_DEFAULT; int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT; try { ITelephony telephony = getITelephony(); @@ -11912,12 +12099,16 @@ 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) public void setCdmaRoamingMode(@CdmaRoamingMode int mode) { + if (Flags.cleanupCdma()) return; if (getPhoneType() != PHONE_TYPE_CDMA) { throw new IllegalStateException("Phone does not support CDMA."); } @@ -11935,7 +12126,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 +12140,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,12 +12185,16 @@ 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) public @CdmaSubscription int getCdmaSubscriptionMode() { + if (Flags.cleanupCdma()) return CDMA_SUBSCRIPTION_UNKNOWN; int mode = CDMA_SUBSCRIPTION_RUIM_SIM; try { ITelephony telephony = getITelephony(); @@ -12022,12 +12229,16 @@ 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) public void setCdmaSubscriptionMode(@CdmaSubscription int mode) { + if (Flags.cleanupCdma()) return; if (getPhoneType() != PHONE_TYPE_CDMA) { throw new IllegalStateException("Phone does not support CDMA."); } @@ -13747,11 +13958,15 @@ 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() { + if (Flags.cleanupCdma()) return null; return getCdmaPrlVersion(getSubId()); } @@ -13762,9 +13977,12 @@ 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) { + if (Flags.cleanupCdma()) return null; try { ITelephony service = getITelephony(); if (service != null) { @@ -13818,6 +14036,7 @@ public class TelephonyManager { * @hide */ @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK) public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) { @@ -14928,7 +15147,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 +15172,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. @@ -15047,7 +15272,10 @@ public class TelephonyManager { | NETWORK_TYPE_BITMASK_LTE_CA | NETWORK_TYPE_BITMASK_NR; - /** @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 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/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java index eaeed2a0a9fa..b1a5b1bebc59 100644 --- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java +++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java @@ -17,6 +17,7 @@ package android.telephony.satellite.stub; import android.annotation.NonNull; +import android.hardware.radio.network.IRadioNetwork; import android.os.IBinder; import android.os.RemoteException; import android.telephony.IBooleanConsumer; @@ -586,7 +587,11 @@ public class SatelliteImplBase extends SatelliteService { * SatelliteResult:SATELLITE_RESULT_NO_RESOURCES * SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE * SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED + * + * @deprecated Use + * {@link IRadioNetwork#setSatellitePlmn(int, int, String[], String[])}. */ + @Deprecated public void setSatellitePlmn(@NonNull int simLogicalSlotIndex, @NonNull List<String> carrierPlmnList, @NonNull List<String> allSatellitePlmnList, @NonNull IIntegerConsumer resultCallback) { @@ -608,7 +613,11 @@ public class SatelliteImplBase extends SatelliteService { * SatelliteResult:SATELLITE_RESULT_MODEM_ERROR * SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE * SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED + * + * @deprecated Use + * {@link IRadioNetwork#setSatelliteEnabledForCarrier(int, int, boolean)}. */ + @Deprecated public void setSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex, @NonNull boolean satelliteEnabled, @NonNull IIntegerConsumer callback) { // stub implementation @@ -629,7 +638,11 @@ public class SatelliteImplBase extends SatelliteService { * SatelliteResult:SATELLITE_RESULT_MODEM_ERROR * SatelliteResult:SATELLITE_RESULT_RADIO_NOT_AVAILABLE * SatelliteResult:SATELLITE_RESULT_REQUEST_NOT_SUPPORTED + * + * @deprecated Use + * {@link IRadioNetwork#isSatelliteEnabledForCarrier(int, int)}. */ + @Deprecated public void requestIsSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex, @NonNull IIntegerConsumer resultCallback, @NonNull IBooleanConsumer callback) { // stub implementation 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/AppJankTest/Android.bp b/tests/AppJankTest/Android.bp index acf8dc9aca47..c3cda6a41cbb 100644 --- a/tests/AppJankTest/Android.bp +++ b/tests/AppJankTest/Android.bp @@ -30,6 +30,7 @@ android_test { "androidx.test.core", "platform-test-annotations", "flag-junit", + "androidx.test.uiautomator_uiautomator", ], platform_apis: true, test_suites: ["device-tests"], diff --git a/tests/AppJankTest/AndroidManifest.xml b/tests/AppJankTest/AndroidManifest.xml index abed1798c47c..861a79c6f0ed 100644 --- a/tests/AppJankTest/AndroidManifest.xml +++ b/tests/AppJankTest/AndroidManifest.xml @@ -19,22 +19,31 @@ package="android.app.jank.tests"> <application android:appCategory="news"> - <uses-library android:name="android.test.runner" /> + <activity android:name=".JankTrackerActivity" + android:exported="true" + android:label="JankTrackerActivity" + android:launchMode="singleTop"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/> + </intent-filter> + </activity> <activity android:name=".EmptyActivity" - android:label="EmptyActivity" - android:exported="true"> + android:exported="true" + android:label="EmptyActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/> </intent-filter> </activity> + <uses-library android:name="android.test.runner"/> </application> <!-- self-instrumenting test package. --> <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="android.app.jank.tests" - android:label="Core tests of App Jank Tracking"> + android:label="Core tests of App Jank Tracking" + android:targetPackage="android.app.jank.tests"> </instrumentation> </manifest>
\ No newline at end of file diff --git a/tests/AppJankTest/res/layout/jank_tracker_activity_layout.xml b/tests/AppJankTest/res/layout/jank_tracker_activity_layout.xml new file mode 100644 index 000000000000..65def7f2d5b6 --- /dev/null +++ b/tests/AppJankTest/res/layout/jank_tracker_activity_layout.xml @@ -0,0 +1,47 @@ +<?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. + --> + + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + + <LinearLayout + android:id="@+id/linear_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + <EditText + android:id="@+id/edit_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textEnableTextConversionSuggestions" + android:text="Edit Text"/> + <TextView android:id="@+id/text_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Text View" + /> + <android.app.jank.tests.TestWidget + android:id="@+id/jank_tracker_widget" + android:layout_width="match_parent" + android:layout_height="wrap_content" + /> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java new file mode 100644 index 000000000000..34f0c191ecf5 --- /dev/null +++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.jank.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import android.app.Activity; +import android.app.Instrumentation; +import android.app.jank.AppJankStats; +import android.app.jank.Flags; +import android.app.jank.JankDataProcessor; +import android.app.jank.JankTracker; +import android.app.jank.StateTracker; +import android.content.Intent; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.widget.EditText; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.rule.ActivityTestRule; +import androidx.test.runner.AndroidJUnit4; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.Until; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * This file contains tests that verify the proper functionality of the Jank Tracking feature. + * All tests should obtain references to necessary objects through View type interfaces, rather + * than direct instantiation. When operating outside of a testing environment, the expected + * behavior is to retrieve the necessary objects using View type interfaces. This approach ensures + * that calls are correctly routed down to the activity level. Any modifications to the call + * routing should result in test failures, which might happen with direct instantiations. + */ +@RunWith(AndroidJUnit4.class) +public class IntegrationTests { + public static final int WAIT_FOR_TIMEOUT_MS = 5000; + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private Activity mEmptyActivity; + + public UiDevice mDevice; + private Instrumentation mInstrumentation; + private ActivityTestRule<JankTrackerActivity> mJankTrackerActivityRule = + new ActivityTestRule<>( + JankTrackerActivity.class, + false, + false); + + private ActivityTestRule<EmptyActivity> mEmptyActivityRule = + new ActivityTestRule<>(EmptyActivity.class, false , true); + + @Before + public void setUp() { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mDevice = UiDevice.getInstance(mInstrumentation); + } + + + /** + * Get a JankTracker object from a view and confirm it's not null. + */ + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void getJankTacker_confirmNotNull() { + Activity jankTrackerActivity = mJankTrackerActivityRule.launchActivity(null); + EditText editText = jankTrackerActivity.findViewById(R.id.edit_text); + + mDevice.wait(Until.findObject(By.text("Edit Text")), WAIT_FOR_TIMEOUT_MS); + + JankTracker jankTracker = editText.getJankTracker(); + assertTrue(jankTracker != null); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void reportJankStats_confirmPendingStatsIncreases() { + Activity jankTrackerActivity = mJankTrackerActivityRule.launchActivity(null); + EditText editText = jankTrackerActivity.findViewById(R.id.edit_text); + JankTracker jankTracker = editText.getJankTracker(); + + HashMap<String, JankDataProcessor.PendingJankStat> pendingStats = + jankTracker.getPendingJankStats(); + assertEquals(0, pendingStats.size()); + + editText.reportAppJankStats(JankUtils.getAppJankStats()); + + // reportAppJankStats performs the work on a background thread, check periodically to see + // if the work is complete. + for (int i = 0; i < 10; i++) { + try { + Thread.sleep(100); + if (jankTracker.getPendingJankStats().size() > 0) { + break; + } + } catch (InterruptedException exception) { + //do nothing and continue + } + } + + pendingStats = jankTracker.getPendingJankStats(); + + assertEquals(1, pendingStats.size()); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void simulateWidgetStateChanges_confirmStateChangesAreTracked() { + JankTrackerActivity jankTrackerActivity = + mJankTrackerActivityRule.launchActivity(null); + TestWidget testWidget = jankTrackerActivity.findViewById(R.id.jank_tracker_widget); + JankTracker jankTracker = testWidget.getJankTracker(); + jankTracker.forceListenerRegistration(); + + ArrayList<StateTracker.StateData> uiStates = new ArrayList<>(); + // Get the current UI states, at this point only the activity name should be in the UI + // states list. + jankTracker.getAllUiStates(uiStates); + + assertEquals(1, uiStates.size()); + + // This should add a UI state to be tracked. + testWidget.simulateAnimationStarting(); + uiStates.clear(); + jankTracker.getAllUiStates(uiStates); + + assertEquals(2, uiStates.size()); + + // Stop the animation + testWidget.simulateAnimationEnding(); + uiStates.clear(); + jankTracker.getAllUiStates(uiStates); + + assertEquals(2, uiStates.size()); + + // Confirm the Animation state has a VsyncIdEnd that is not default, indicating the end + // of that state. + for (int i = 0; i < uiStates.size(); i++) { + StateTracker.StateData stateData = uiStates.get(i); + if (stateData.mWidgetCategory.equals(AppJankStats.ANIMATION)) { + assertNotEquals(Long.MAX_VALUE, stateData.mVsyncIdEnd); + } + } + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void jankTrackingPaused_whenActivityNoLongerVisible() { + JankTrackerActivity jankTrackerActivity = + mJankTrackerActivityRule.launchActivity(null); + TestWidget testWidget = jankTrackerActivity.findViewById(R.id.jank_tracker_widget); + JankTracker jankTracker = testWidget.getJankTracker(); + jankTracker.forceListenerRegistration(); + + assertTrue(jankTracker.shouldTrack()); + + // Send jankTrackerActivity to the background + mDevice.pressHome(); + mDevice.waitForIdle(WAIT_FOR_TIMEOUT_MS); + + assertFalse(jankTracker.shouldTrack()); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) + public void jankTrackingResumed_whenActivityBecomesVisibleAgain() { + mEmptyActivityRule.launchActivity(null); + mEmptyActivity = mEmptyActivityRule.getActivity(); + JankTrackerActivity jankTrackerActivity = + mJankTrackerActivityRule.launchActivity(null); + TestWidget testWidget = jankTrackerActivity.findViewById(R.id.jank_tracker_widget); + JankTracker jankTracker = testWidget.getJankTracker(); + jankTracker.forceListenerRegistration(); + + // Send jankTrackerActivity to the background + mDevice.pressHome(); + mDevice.waitForIdle(WAIT_FOR_TIMEOUT_MS); + + assertFalse(jankTracker.shouldTrack()); + + Intent resumeJankTracker = new Intent(mInstrumentation.getContext(), + JankTrackerActivity.class); + resumeJankTracker.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + mEmptyActivity.startActivity(resumeJankTracker); + mDevice.wait(Until.findObject(By.text("Edit Text")), WAIT_FOR_TIMEOUT_MS); + + assertTrue(jankTracker.shouldTrack()); + } +} diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java index 4d495adf727b..30c568be7716 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankDataProcessorTest.java @@ -20,7 +20,6 @@ import static org.junit.Assert.assertEquals; import android.app.jank.AppJankStats; import android.app.jank.Flags; -import android.app.jank.FrameOverrunHistogram; import android.app.jank.JankDataProcessor; import android.app.jank.StateTracker; import android.platform.test.annotations.RequiresFlagsEnabled; @@ -165,7 +164,7 @@ public class JankDataProcessorTest { assertEquals(pendingStats.size(), 0); - AppJankStats jankStats = getAppJankStats(); + AppJankStats jankStats = JankUtils.getAppJankStats(); mJankDataProcessor.mergeJankStats(jankStats, sActivityName); pendingStats = mJankDataProcessor.getPendingJankStats(); @@ -182,14 +181,14 @@ public class JankDataProcessorTest { @Test @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public void mergeAppJankStats_confirmStatsWithMatchingStatesAreCombinedIntoOnePendingStat() { - AppJankStats jankStats = getAppJankStats(); + AppJankStats jankStats = JankUtils.getAppJankStats(); mJankDataProcessor.mergeJankStats(jankStats, sActivityName); HashMap<String, JankDataProcessor.PendingJankStat> pendingStats = mJankDataProcessor.getPendingJankStats(); assertEquals(pendingStats.size(), 1); - AppJankStats secondJankStat = getAppJankStats(); + AppJankStats secondJankStat = JankUtils.getAppJankStats(); mJankDataProcessor.mergeJankStats(secondJankStat, sActivityName); pendingStats = mJankDataProcessor.getPendingJankStats(); @@ -200,7 +199,7 @@ public class JankDataProcessorTest { @Test @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public void mergeAppJankStats_whenStatsWithMatchingStatesMerge_confirmFrameCountsAdded() { - AppJankStats jankStats = getAppJankStats(); + AppJankStats jankStats = JankUtils.getAppJankStats(); mJankDataProcessor.mergeJankStats(jankStats, sActivityName); mJankDataProcessor.mergeJankStats(jankStats, sActivityName); @@ -345,27 +344,4 @@ public class JankDataProcessorTest { return mockData; } - - private AppJankStats getAppJankStats() { - AppJankStats jankStats = new AppJankStats( - /*App Uid*/APP_ID, - /*Widget Id*/"test widget id", - /*Widget Category*/AppJankStats.SCROLL, - /*Widget State*/AppJankStats.SCROLLING, - /*Total Frames*/100, - /*Janky Frames*/25, - getOverrunHistogram() - ); - return jankStats; - } - - private FrameOverrunHistogram getOverrunHistogram() { - FrameOverrunHistogram overrunHistogram = new FrameOverrunHistogram(); - overrunHistogram.addFrameOverrunMillis(-2); - overrunHistogram.addFrameOverrunMillis(1); - overrunHistogram.addFrameOverrunMillis(5); - overrunHistogram.addFrameOverrunMillis(25); - return overrunHistogram; - } - } diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java new file mode 100644 index 000000000000..80ab6ad3e587 --- /dev/null +++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.jank.tests; + +import android.app.Activity; +import android.os.Bundle; + + +public class JankTrackerActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.jank_tracker_activity_layout); + } +} + + diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java new file mode 100644 index 000000000000..0b4d97ed20d6 --- /dev/null +++ b/tests/AppJankTest/src/android/app/jank/tests/JankUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.jank.tests; + +import android.app.jank.AppJankStats; +import android.app.jank.FrameOverrunHistogram; + +public class JankUtils { + private static final int APP_ID = 25; + + /** + * Returns a mock AppJankStats object to be used in tests. + */ + public static AppJankStats getAppJankStats() { + AppJankStats jankStats = new AppJankStats( + /*App Uid*/APP_ID, + /*Widget Id*/"test widget id", + /*Widget Category*/AppJankStats.SCROLL, + /*Widget State*/AppJankStats.SCROLLING, + /*Total Frames*/100, + /*Janky Frames*/25, + getOverrunHistogram() + ); + return jankStats; + } + + /** + * Returns a mock histogram to be used with an AppJankStats object. + */ + public static FrameOverrunHistogram getOverrunHistogram() { + FrameOverrunHistogram overrunHistogram = new FrameOverrunHistogram(); + overrunHistogram.addFrameOverrunMillis(-2); + overrunHistogram.addFrameOverrunMillis(1); + overrunHistogram.addFrameOverrunMillis(5); + overrunHistogram.addFrameOverrunMillis(25); + return overrunHistogram; + } +} diff --git a/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java new file mode 100644 index 000000000000..5fff46038ead --- /dev/null +++ b/tests/AppJankTest/src/android/app/jank/tests/TestWidget.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.jank.tests; + +import android.app.jank.AppJankStats; +import android.app.jank.JankTracker; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; + +public class TestWidget extends View { + + private JankTracker mJankTracker; + + /** + * Create JankTrackerView + */ + public TestWidget(Context context) { + super(context); + } + + /** + * Create JankTrackerView, needed by system when inflating views defined in a layout file. + */ + public TestWidget(Context context, AttributeSet attributeSet) { + super(context, attributeSet); + } + + /** + * Mock starting an animation. + */ + public void simulateAnimationStarting() { + if (jankTrackerCreated()) { + mJankTracker.addUiState(AppJankStats.ANIMATION, + Integer.toString(this.getId()), AppJankStats.ANIMATING); + } + } + + /** + * Mock ending an animation. + */ + public void simulateAnimationEnding() { + if (jankTrackerCreated()) { + mJankTracker.removeUiState(AppJankStats.ANIMATION, + Integer.toString(this.getId()), AppJankStats.ANIMATING); + } + } + + private boolean jankTrackerCreated() { + if (mJankTracker == null) { + mJankTracker = getJankTracker(); + } + return mJankTracker != null; + } +} 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/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/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java index ad032fb2fba6..15a580c9e8f7 100644 --- a/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java +++ b/tests/broadcasts/unit/src/android/app/BroadcastStickyCacheTest.java @@ -20,6 +20,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; @@ -186,6 +187,22 @@ public class BroadcastStickyCacheTest { } @Test + public void getIntent_queryActionTwiceWithNullResult_verifyRegisterReceiverIsCalledOnce() + throws RemoteException { + setActivityManagerMock(null); + final Intent intent = queryIntent(new IntentFilter(Intent.ACTION_DEVICE_STORAGE_FULL)); + final Intent cachedIntent = queryIntent( + new IntentFilter(Intent.ACTION_DEVICE_STORAGE_FULL)); + + assertNull(intent); + assertNull(cachedIntent); + + verify(mActivityManagerMock, times(1)).registerReceiverWithFeature( + eq(mIApplicationThreadMock), anyString(), anyString(), anyString(), any(), + any(), anyString(), anyInt(), anyInt()); + } + + @Test public void getIntent_querySameActionWithDifferentFilter_verifyRegisterReceiverCalledTwice() throws RemoteException { setActivityManagerMock(Intent.ACTION_DEVICE_STORAGE_LOW); @@ -226,6 +243,6 @@ public class BroadcastStickyCacheTest { when(ActivityManager.getService()).thenReturn(mActivityManagerMock); when(mActivityManagerMock.registerReceiverWithFeature(any(), anyString(), anyString(), anyString(), any(), any(), anyString(), anyInt(), - anyInt())).thenReturn(new Intent(action)); + anyInt())).thenReturn(action != null ? new Intent(action) : null); } } 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); + } } |