diff options
140 files changed, 12181 insertions, 1582 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 6367002a6693..e871c7383843 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -44888,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"; @@ -44919,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"; @@ -45070,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"; @@ -45103,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"; @@ -45113,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"; @@ -45549,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 { @@ -45647,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 { @@ -47230,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(); @@ -47380,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 @@ -47403,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"; @@ -47446,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 @@ -47468,12 +47468,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 @@ -47488,7 +47488,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 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4a4776dc590e..1c185899c2bb 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -14630,7 +14630,7 @@ package android.telecom { field public static final int CALLTYPE_INCOMING = 1; // 0x1 field public static final int CALLTYPE_OUTGOING = 2; // 0x2 field public static final int CALLTYPE_UNKNOWN = 0; // 0x0 - field public static final int CDMA_PHONE = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PHONE = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics> CREATOR; field public static final int GSM_PHONE = 2; // 0x2 field public static final int IMS_PHONE = 4; // 0x4 @@ -15011,7 +15011,7 @@ package android.telephony { field public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT = "gba_ua_security_organization_int"; field public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int"; field public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int"; - field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; } public static final class CarrierConfigManager.Wifi { @@ -15098,8 +15098,8 @@ package android.telephony { ctor public CellBroadcastService(); method @NonNull @WorkerThread public abstract CharSequence getCellBroadcastAreaInfo(int); method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent); - method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int); - method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaCellBroadcastSms(int, @NonNull byte[], int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>); method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]); field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; } @@ -15109,9 +15109,9 @@ package android.telephony { method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo(); } - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); } public final class CellIdentityGsm extends android.telephony.CellIdentity { @@ -15527,16 +15527,16 @@ package android.telephony { field public static final int BUSY = 17; // 0x11 field public static final int CALL_BARRED = 240; // 0xf0 field public static final int CALL_REJECTED = 21; // 0x15 - field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 - field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee - field public static final int CDMA_DROP = 1001; // 0x3e9 - field public static final int CDMA_INTERCEPT = 1002; // 0x3ea - field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 - field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 - field public static final int CDMA_PREEMPTED = 1007; // 0x3ef - field public static final int CDMA_REORDER = 1003; // 0x3eb - field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed - field public static final int CDMA_SO_REJECT = 1004; // 0x3ec + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_DROP = 1001; // 0x3e9 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_INTERCEPT = 1002; // 0x3ea + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PREEMPTED = 1007; // 0x3ef + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_REORDER = 1003; // 0x3eb + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SO_REJECT = 1004; // 0x3ec field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6 field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 @@ -16070,14 +16070,14 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageName(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageNameForLogicalSlot(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); - method public String getCdmaPrlVersion(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public String getCdmaPrlVersion(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public java.util.List<android.telephony.CellBroadcastIdRange> getCellBroadcastIdRanges(); method public int getCurrentPhoneType(); method public int getCurrentPhoneType(int); @@ -16167,7 +16167,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); @@ -16176,8 +16176,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); method @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public void setCellBroadcastIdRanges(@NonNull java.util.List<android.telephony.CellBroadcastIdRange>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); @@ -16241,9 +16241,9 @@ package android.telephony { field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff - field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 - field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 - field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff field public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3; // 0x3 field public static final int CELL_BROADCAST_RESULT_FAIL_CONFIG = 2; // 0x2 field public static final int CELL_BROADCAST_RESULT_SUCCESS = 0; // 0x0 @@ -16460,21 +16460,21 @@ package android.telephony { package android.telephony.cdma { - public final class CdmaSmsCbProgramData implements android.os.Parcelable { - method public int describeContents(); - method public int getCategory(); - method public int getOperation(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 - field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 - field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff - field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 - field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 - field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR; - field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 - field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 - field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CdmaSmsCbProgramData implements android.os.Parcelable { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int describeContents(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getCategory(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getOperation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void writeToParcel(android.os.Parcel, int); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 } } @@ -17802,7 +17802,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 diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl index 56ed290baf2e..b4dee2e937cb 100644 --- a/core/java/android/app/AppOpsManager.aidl +++ b/core/java/android/app/AppOpsManager.aidl @@ -19,7 +19,6 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEvent; -parcelable AppOpsManager.NotedOp; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpEntry; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index c789e28cdbab..19138126698c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -262,24 +262,6 @@ public class AppOpsManager { private static final Object sLock = new Object(); - // A map that records noted times for each op. - private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>(); - private final HandlerThread mHandlerThread; - private final Handler mHandler; - private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000; - - private boolean isNoteOpBatchingSupported() { - // If noteOp is called from system server no IPC is made, hence we don't need batching. - if (Process.myUid() == Process.SYSTEM_UID) { - return false; - } - return Flags.noteOpBatchingEnabled(); - } - - private final Object mBatchedNoteOpLock = new Object(); - @GuardedBy("mBatchedNoteOpLock") - private boolean mIsBatchedNoteOpCallScheduled = false; - /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ @GuardedBy("sLock") private static @Nullable OnOpNotedCallback sOnOpNotedCallback; @@ -7484,135 +7466,6 @@ public class AppOpsManager { } /** - * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch - * - * @hide - */ - public static final class NotedOp implements Parcelable { - private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp; - private final @IntRange(from = 0) int mUid; - private final @Nullable String mPackageName; - private final @Nullable String mAttributionTag; - private final int mVirtualDeviceId; - private final @Nullable String mMessage; - private final boolean mShouldCollectAsyncNotedOp; - private final boolean mShouldCollectMessage; - - public NotedOp(int op, int uid, @Nullable String packageName, - @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, - boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) { - mOp = op; - mUid = uid; - mPackageName = packageName; - mAttributionTag = attributionTag; - mVirtualDeviceId = virtualDeviceId; - mMessage = message; - mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp; - mShouldCollectMessage = shouldCollectMessage; - } - - NotedOp(Parcel source) { - mOp = source.readInt(); - mUid = source.readInt(); - mPackageName = source.readString(); - mAttributionTag = source.readString(); - mVirtualDeviceId = source.readInt(); - mMessage = source.readString(); - mShouldCollectAsyncNotedOp = source.readBoolean(); - mShouldCollectMessage = source.readBoolean(); - } - - public int getOp() { - return mOp; - } - - public int getUid() { - return mUid; - } - - public @Nullable String getPackageName() { - return mPackageName; - } - - public @Nullable String getAttributionTag() { - return mAttributionTag; - } - - public int getVirtualDeviceId() { - return mVirtualDeviceId; - } - - public @Nullable String getMessage() { - return mMessage; - } - - public boolean getShouldCollectAsyncNotedOp() { - return mShouldCollectAsyncNotedOp; - } - - public boolean getShouldCollectMessage() { - return mShouldCollectMessage; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mOp); - dest.writeInt(mUid); - dest.writeString(mPackageName); - dest.writeString(mAttributionTag); - dest.writeInt(mVirtualDeviceId); - dest.writeString(mMessage); - dest.writeBoolean(mShouldCollectAsyncNotedOp); - dest.writeBoolean(mShouldCollectMessage); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - NotedOp that = (NotedOp) o; - return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName, - that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag) - && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage, - that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp, - that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage, - that.mShouldCollectMessage); - } - - @Override - public int hashCode() { - return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId, - mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage); - } - - @Override - public String toString() { - return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName - + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId=" - + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp=" - + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage=" - + mShouldCollectMessage + "}"; - } - - - public static final @NonNull Creator<NotedOp> CREATOR = - new Creator<>() { - @Override public NotedOp createFromParcel(Parcel source) { - return new NotedOp(source); - } - - @Override public NotedOp[] newArray(int size) { - return new NotedOp[size]; - } - }; - } - - /** * Computes the sum of the counts for the given flags in between the begin and * end UID states. * @@ -8126,9 +7979,6 @@ public class AppOpsManager { AppOpsManager(Context context, IAppOpsService service) { mContext = context; mService = service; - mHandlerThread = new HandlerThread("AppOpsManager"); - mHandlerThread.start(); - mHandler = mHandlerThread.getThreadHandler(); if (mContext != null) { final PackageManager pm = mContext.getPackageManager(); @@ -9465,74 +9315,15 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = null; - boolean skipBinderCall = false; - if (isNoteOpBatchingSupported()) { - int mode = sAppOpModeCache.query( - new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, - "noteOpNoThrow")); - // For FOREGROUND mode, we still need to make a binder call to the system service - // to translate it to ALLOWED or IGNORED. So no batching is needed. - if (mode != MODE_FOREGROUND) { - synchronized (mBatchedNoteOpLock) { - NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag, - virtualDeviceId, message, collectionMode == COLLECT_ASYNC, - shouldCollectMessage); - - // Batch same noteOp calls and send them with their counters to the system - // service asynchronously. The time window for batching is specified in - // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go - // through binder API. Accumulate subsequent same noteOp calls during the - // time window in mPendingNotedOps. - if (!mPendingNotedOps.containsKey(notedOp)) { - mPendingNotedOps.put(notedOp, 0); - } else { - skipBinderCall = true; - mPendingNotedOps.merge(notedOp, 1, Integer::sum); - } - - if (!mIsBatchedNoteOpCallScheduled) { - mHandler.postDelayed(() -> { - ArrayMap<NotedOp, Integer> pendingNotedOpsCopy; - synchronized(mBatchedNoteOpLock) { - mIsBatchedNoteOpCallScheduled = false; - pendingNotedOpsCopy = - new ArrayMap<NotedOp, Integer>(mPendingNotedOps); - mPendingNotedOps.clear(); - } - for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) { - if (pendingNotedOpsCopy.valueAt(i) == 0) { - pendingNotedOpsCopy.removeAt(i); - } - } - if (!pendingNotedOpsCopy.isEmpty()) { - try { - mService.noteOperationsInBatch(pendingNotedOpsCopy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - }, NOTE_OP_BATCHING_DELAY_MILLIS); - - mIsBatchedNoteOpCallScheduled = true; - } - } - - syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName); - } - } - - if (!skipBinderCall) { - if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { - syncOp = mService.noteOperation(op, uid, packageName, attributionTag, - collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); - } else { - syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, - virtualDeviceId, collectionMode == COLLECT_ASYNC, message, - shouldCollectMessage); - } + SyncNotedAppOp syncOp; + if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { + syncOp = mService.noteOperation(op, uid, packageName, attributionTag, + collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); + } else { + syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, + virtualDeviceId, collectionMode == COLLECT_ASYNC, message, + shouldCollectMessage); } - if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { collectNotedOpForSelf(syncOp); diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 8b7ea0f8b46a..b21defbcc0e3 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; @@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal { */ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, Integer, SyncNotedAppOp> superImpl); + @Nullable String message, boolean shouldCollectMessage, + @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, SyncNotedAppOp> superImpl); /** * Allows overriding note proxy operation behavior. diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java index fe2e10752355..0b6cf59876d2 100644 --- a/core/java/android/app/BroadcastStickyCache.java +++ b/core/java/android/app/BroadcastStickyCache.java @@ -35,6 +35,7 @@ import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.view.WindowManagerPolicyConstants; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -71,8 +72,10 @@ public class BroadcastStickyCache { @VisibleForTesting public static final ArrayMap<String, String> sActionApiNameMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap<String, IpcDataCache.Config> sActionConfigMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap<StickyBroadcastFilter, IpcDataCache<Void, Intent>> sFilterCacheMap = new ArrayMap<>(); @@ -154,37 +157,44 @@ public class BroadcastStickyCache { @Nullable String broadcastPermission, @UserIdInt int userId, @RegisterReceiverFlags int flags) { - IpcDataCache<Void, Intent> intentDataCache = findIpcDataCache(filter); - - if (intentDataCache == null) { - final String action = filter.getAction(0); - final StickyBroadcastFilter stickyBroadcastFilter = - new StickyBroadcastFilter(filter, action); - final Config config = getConfig(action); - - intentDataCache = - new IpcDataCache<>(config, - (query) -> ActivityManager.getService().registerReceiverWithFeature( - applicationThread, - mBasePackageName, - attributionTag, - /* receiverId= */ "null", - /* receiver= */ null, - filter, - broadcastPermission, - userId, - flags)); - sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + IpcDataCache<Void, Intent> intentDataCache; + + synchronized (BroadcastStickyCache.class) { + intentDataCache = findIpcDataCache(filter); + + if (intentDataCache == null) { + final String action = filter.getAction(0); + final StickyBroadcastFilter stickyBroadcastFilter = + new StickyBroadcastFilter(filter, action); + final Config config = getConfig(action); + + intentDataCache = + new IpcDataCache<>(config, + (query) -> ActivityManager.getService().registerReceiverWithFeature( + applicationThread, + mBasePackageName, + attributionTag, + /* receiverId= */ "null", + /* receiver= */ null, + filter, + broadcastPermission, + userId, + flags)); + sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + } } return intentDataCache.query(null); } @VisibleForTesting public static void clearCacheForTest() { - sFilterCacheMap.clear(); + synchronized (BroadcastStickyCache.class) { + sFilterCacheMap.clear(); + } } @Nullable + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache<Void, Intent> findIpcDataCache( @NonNull IntentFilter filter) { for (int i = sFilterCacheMap.size() - 1; i >= 0; i--) { @@ -198,6 +208,7 @@ public class BroadcastStickyCache { } @NonNull + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache.Config getConfig(@NonNull String action) { if (!sActionConfigMap.containsKey(action)) { // We only need 1 entry per cache but just to be on the safer side we are choosing 32 diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index 7ceaeb3fb070..c9472598b352 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -215,7 +215,8 @@ public class JankDataProcessor { try { mPendingJankStats.values().forEach(stat -> { - FrameworkStatsLog.write(FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET, + FrameworkStatsLog.write( + FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET_REPORTED, /*app uid*/ stat.getUid(), /*activity name*/ stat.getActivityName(), /*widget id*/ stat.getWidgetId(), diff --git a/core/java/android/companion/DeviceId.java b/core/java/android/companion/DeviceId.java index d9514a02c2b4..2f19eb49ad43 100644 --- a/core/java/android/companion/DeviceId.java +++ b/core/java/android/companion/DeviceId.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.net.MacAddress; import android.os.Parcel; import android.os.Parcelable; -import android.provider.OneTimeUseBuilder; import java.util.Locale; import java.util.Objects; @@ -159,7 +158,7 @@ public final class DeviceId implements Parcelable { * the device: a custom ID using {@link #setCustomId(String)}, or a MAC address using * {@link #setMacAddress(MacAddress)}.</p> */ - public static final class Builder extends OneTimeUseBuilder<DeviceId> { + public static final class Builder { private String mCustomId; private MacAddress mMacAddress; @@ -175,7 +174,6 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setCustomId(@Nullable String customId) { - checkNotUsed(); if (customId != null && customId.length() > CUSTOM_ID_LENGTH_LIMIT) { throw new IllegalArgumentException("Length of the custom id must be at most " @@ -195,15 +193,12 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setMacAddress(@Nullable MacAddress macAddress) { - checkNotUsed(); mMacAddress = macAddress; return this; } @NonNull - @Override public DeviceId build() { - markUsed(); if (mCustomId == null && mMacAddress == null) { throw new IllegalArgumentException("At least one device id property must be" + "non-null to build a DeviceId."); diff --git a/core/java/android/hardware/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/view/InsetsState.java b/core/java/android/view/InsetsState.java index 67050e01b591..213ece09da22 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -296,8 +296,8 @@ public class InsetsState implements Parcelable { @SoftInputModeFlags int softInputMode, int windowFlags) { final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST; final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING - ? systemBars() | ime() - : systemBars(); + ? systemBars() | displayCutout() | ime() + : systemBars() | displayCutout(); @InsetsType int forceConsumingTypes = 0; Insets insets = Insets.NONE; for (int i = mSources.size() - 1; i >= 0; i--) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0681745a0fc6..d15b0f518f83 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17184,7 +17184,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); final Insets insets = metrics.getWindowInsets().getInsets( - WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()); + WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); outRect.set(metrics.getBounds()); outRect.inset(insets); outRect.offsetTo(0, 0); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 1de0474182dd..60e528c5fb58 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -26,6 +26,7 @@ import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.service.autofill.Flags.relayoutFix; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.autofill.Helper.sDebug; @@ -787,6 +788,11 @@ public final class AutofillManager { private AutofillStateFingerprint mAutofillStateFingerprint; + /** + * Whether improveFillDialog feature is enabled or not. + */ + private boolean mImproveFillDialogEnabled; + /** @hide */ public interface AutofillClient { /** @@ -1017,6 +1023,17 @@ public final class AutofillManager { mRelayoutFix = relayoutFix() && AutofillFeatureFlags.enableRelayoutFixes(); mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout(); mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + } + + /** + * Whether improvement to fill dialog is enabled. + * + * @hide + */ + public boolean isImproveFillDialogEnabled() { + return mImproveFillDialogEnabled; } /** @@ -1679,6 +1696,11 @@ public final class AutofillManager { private void notifyViewReadyInner(AutofillId id, @Nullable String[] autofillHints, boolean isCredmanRequested) { + if (isImproveFillDialogEnabled() && !isCredmanRequested) { + // We do not want to send pre-trigger request. + // TODO(b/377868687): verify if we can remove the flow for isCredmanRequested too. + return; + } if (sDebug) { Log.d(TAG, "notifyViewReadyInner:" + id); } @@ -2046,6 +2068,34 @@ public final class AutofillManager { } /** + * Notify autofill system that IME animation has started + * @param startTimeMs start time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationStart(long startTimeMs) { + try { + mService.notifyImeAnimationStart(mSessionId, startTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** + * Notify autofill system that IME animation has ended + * @param endTimeMs end time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationEnd(long endTimeMs) { + try { + mService.notifyImeAnimationEnd(mSessionId, endTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** * Called when a virtual view that supports autofill is exited. * * @param view the virtual view parent. @@ -4050,6 +4100,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, view.getAutofillId())) { mShowAutofillDialogCalled = true; @@ -4093,6 +4147,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view, int virtualId) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) { mShowAutofillDialogCalled = true; @@ -4117,7 +4175,7 @@ public final class AutofillManager { return false; } - if (getImeStateFlag(view) == FLAG_IME_SHOWING) { + if (getImeStateFlag(view) == FLAG_IME_SHOWING && !isImproveFillDialogEnabled()) { // IME is showing return false; } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index f67405f7c1e4..28f8577beed7 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -70,4 +70,6 @@ oneway interface IAutoFillManager { void notifyNotExpiringResponseDuringAuth(int sessionId, int userId); void notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int userId); void setAutofillIdsAttemptedForRefill(int sessionId, in List<AutofillId> ids, int userId); + void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId); + void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId); } diff --git a/core/java/android/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/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/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/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 9bf4d65e1865..2e885145819c 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -34,6 +34,7 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.text.TextRunShaper; import android.os.Build; @@ -2141,6 +2142,14 @@ public class Paint { * @see FontVariationAxis */ public boolean setFontVariationSettings(String fontVariationSettings) { + return setFontVariationSettings(fontVariationSettings, 0 /* wght adjust */); + } + + /** + * Set font variation settings with weight adjustment + * @hide + */ + public boolean setFontVariationSettings(String fontVariationSettings, int wghtAdjust) { final boolean useFontVariationStore = Flags.typefaceRedesignReadonly() && CompatChanges.isChangeEnabled(NEW_FONT_VARIATION_MANAGEMENT); if (useFontVariationStore) { @@ -2154,8 +2163,13 @@ public class Paint { long builderPtr = nCreateFontVariationBuilder(axes.length); for (int i = 0; i < axes.length; ++i) { - nAddFontVariationToBuilder(builderPtr, axes[i].getOpenTypeTagValue(), - axes[i].getStyleValue()); + int tag = axes[i].getOpenTypeTagValue(); + float value = axes[i].getStyleValue(); + if (tag == 0x77676874 /* wght */) { + value = Math.clamp(value + wghtAdjust, + FontStyle.FONT_WEIGHT_MIN, FontStyle.FONT_WEIGHT_MAX); + } + nAddFontVariationToBuilder(builderPtr, tag, value); } nSetFontVariationOverride(mNativePaint, builderPtr); mFontVariationSettings = fontVariationSettings; diff --git a/libs/WindowManager/Shell/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 a5205ee24d05..4c77eaf80a29 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java @@ -91,6 +91,9 @@ public class DesktopModeStatus { /** The maximum override density allowed for tasks inside the desktop. */ private static final int DESKTOP_DENSITY_MAX = 1000; + /** The number of [WindowDecorViewHost] instances to warm up on system start. */ + private static final int WINDOW_DECOR_PRE_WARM_SIZE = 2; + /** * Sysprop declaring whether to enters desktop mode by default when the windowing mode of the * display's root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM. @@ -122,6 +125,14 @@ public class DesktopModeStatus { private static final String MAX_TASK_LIMIT_SYS_PROP = "persist.wm.debug.desktop_max_task_limit"; /** + * Sysprop declaring the number of [WindowDecorViewHost] instances to warm up on system start. + * + * <p>If it is not defined, then [WINDOW_DECOR_PRE_WARM_SIZE] is used. + */ + private static final String WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP = + "persist.wm.debug.desktop_window_decor_pre_warm_size"; + + /** * Return {@code true} if veiled resizing is active. If false, fluid resizing is used. */ public static boolean isVeiledResizeEnabled() { @@ -176,6 +187,12 @@ public class DesktopModeStatus { 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. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt index ef964f40dab3..8e149ac2869a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt @@ -66,3 +66,41 @@ infix fun LetterboxController.append(other: LetterboxController) = object : Lett other.dump() } } + +object LetterboxUtils { + // Utility methods about Maps usage in Letterbox. + object Maps { + /* + * Executes [onFound] on the [item] for a given [key] if present or + * [onMissed] if the [key] is not present. + */ + fun <V, K> MutableMap<K, V>.runOnItem( + key: K, + onFound: (V) -> Unit = { _ -> }, + onMissed: ( + K, + MutableMap<K, V> + ) -> Unit = { _, _ -> } + ) { + this[key]?.let { + return onFound(it) + } + return onMissed(key, this) + } + } + + // Utility methods about Transaction usage in Letterbox. + object Transactions { + // Sets position and crops in one method. + fun Transaction.moveAndCrop( + surface: SurfaceControl, + rect: Rect + ): Transaction = + setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) + .setWindowCrop( + surface, + rect.width(), + rect.height() + ) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt index 5129d03b9dbc..6861aa3763b5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -101,23 +103,6 @@ class MultiSurfaceLetterboxController @Inject constructor( ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - /* - * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, LetterboxSurfaces>.runOnItem( - key: LetterboxKey, - onFound: (LetterboxSurfaces) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, LetterboxSurfaces> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - private fun SurfaceControl?.remove( tx: Transaction ) = this?.let { @@ -131,17 +116,6 @@ class MultiSurfaceLetterboxController @Inject constructor( tx.setVisibility(this, visible) } - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) - private fun LetterboxSurfaces.updateSurfacesBounds( tx: Transaction, taskBounds: Rect, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt index a67f6082c892..8e1cdee0c862 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -106,32 +108,4 @@ class SingleSurfaceLetterboxController @Inject constructor( override fun dump() { ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - - /* - * Executes [onFound] on the [SurfaceControl] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, SurfaceControl>.runOnItem( - key: LetterboxKey, - onFound: (SurfaceControl) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, SurfaceControl> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index f9e3be9c770f..0cd0f4a97bbf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -349,10 +349,13 @@ public abstract class WMShellModule { @Provides static WindowDecorViewHostSupplier<WindowDecorViewHost> provideWindowDecorViewHostSupplier( @NonNull Context context, - @ShellMainThread @NonNull CoroutineScope mainScope) { + @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(mainScope, poolSize); + return new PooledWindowDecorViewHostSupplier( + context, mainScope, shellInit, poolSize, preWarmSize); } return new DefaultWindowDecorViewHostSupplier(mainScope); } 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 index adb0ba643e0d..47cfaeed6157 100644 --- 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 @@ -21,25 +21,57 @@ 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. + * 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) { @@ -64,7 +96,7 @@ class PooledWindowDecorViewHostSupplier( context = context, mainScope = mainScope, display = display, - id = nextDecorViewHostId++ + 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 index bf0b1186254f..da41e1b1d8d8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt @@ -17,11 +17,15 @@ 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 @@ -35,6 +39,9 @@ import kotlinx.coroutines.launch * 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, @@ -44,7 +51,7 @@ class ReusableWindowDecorViewHost( @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter = SurfaceControlViewHostAdapter(context, display), -) : WindowDecorViewHost { +) : WindowDecorViewHost, Warmable { @VisibleForTesting val rootView = FrameLayout(context) private var currentUpdateJob: Job? = null @@ -52,6 +59,30 @@ class ReusableWindowDecorViewHost( 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, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt new file mode 100644 index 000000000000..2cb0f891436b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor.common.viewhost + +/** + * An interface for an object that can be warmed up before it's needed. + */ +interface Warmable { + fun warmUp() +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt index 06b805233ee7..667511288bfa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt @@ -19,9 +19,14 @@ package com.android.wm.shell.compatui.letterbox import android.content.Context import android.graphics.Rect import android.testing.AndroidTestingRunner +import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import java.util.function.Consumer +import kotlin.test.assertEquals +import kotlin.test.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any @@ -100,6 +105,35 @@ class LetterboxUtilsTest : ShellTestCase() { } } + @Test + fun `runOnItem executes onFound when an item has been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(1) + r.verifyOnItemInvoked(expectedItem = 2) + r.verifyOnMissingNotInvoked() + } + } + + @Test + fun `runOnItem executes onMissing when an item has not been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(8) + r.verifyOnItemNotInvoked() + r.verifyOnMissingInvoked(expectedKey = 8) + } + } + + @Test + fun `moveAndCrop invoked Move and then Crop`() { + runTestScenario { r -> + r.invoke(Rect(1, 2, 51, 62)) + r.verifySetPosition(expectedX = 1f, expectedY = 2f) + r.verifySetWindowCrop(expectedWidth = 50, expectedHeight = 60) + } + } + /** * Runs a test scenario providing a Robot. */ @@ -113,6 +147,14 @@ class LetterboxUtilsTest : ShellTestCase() { builder: (LetterboxSurfaceBuilder) -> LetterboxController ) : LetterboxControllerRobotTest(ctx, builder) { + private var testableMap = mutableMapOf<Int, Int>() + private var onItemState: Int? = null + private var onMissingStateKey: Int? = null + private var onMissingStateMap: MutableMap<Int, Int>? = null + + private val transaction = getTransactionMock() + private val surface = SurfaceControl() + fun verifyCreateSurfaceInvokedWithRequest( target: LetterboxController, times: Int = 1 @@ -147,5 +189,46 @@ class LetterboxUtilsTest : ShellTestCase() { ) { verify(target, times(times)).dump() } + + fun initMap(vararg values: Pair<Int, Int>) = testableMap.putAll(values.toMap()) + + fun <T> runOnItem(key: Int) { + testableMap.runOnItem(key, onFound = { item -> + onItemState = item + }, onMissed = { k, m -> + onMissingStateKey = k + onMissingStateMap = m + }) + } + + fun verifyOnItemInvoked(expectedItem: Int) { + assertEquals(expectedItem, onItemState) + } + + fun verifyOnItemNotInvoked() { + assertNull(onItemState) + } + + fun verifyOnMissingInvoked(expectedKey: Int) { + assertEquals(expectedKey, onMissingStateKey) + assertEquals(onMissingStateMap, testableMap) + } + + fun verifyOnMissingNotInvoked() { + assertNull(onMissingStateKey) + assertNull(onMissingStateMap) + } + + fun invoke(rect: Rect) { + transaction.moveAndCrop(surface, rect) + } + + fun verifySetPosition(expectedX: Float, expectedY: Float) { + verify(transaction).setPosition(surface, expectedX, expectedY) + } + + fun verifySetWindowCrop(expectedWidth: Int, expectedHeight: Int) { + verify(transaction).setWindowCrop(surface, expectedWidth, expectedHeight) + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplierTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplierTest.kt index 40583f80003c..92f5def508c7 100644 --- 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 @@ -18,14 +18,19 @@ 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 @@ -38,9 +43,13 @@ import org.mockito.kotlin.mock * 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 @@ -48,6 +57,27 @@ class PooledWindowDecorViewHostSupplierTest : ShellTestCase() { 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) @@ -97,8 +127,9 @@ class PooledWindowDecorViewHostSupplierTest : ShellTestCase() { assertThat(viewHost2.released).isTrue() } - private fun CoroutineScope.createSupplier(maxPoolSize: Int) = - PooledWindowDecorViewHostSupplier(this, maxPoolSize) + 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 diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt index 245393a6d44e..d99a4825e580 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt @@ -157,6 +157,14 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { 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, 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/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/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 4eb0567c67d9..b58983ff1ce8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth; import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice; +import static com.android.settingslib.flags.Flags.ignoreA2dpDisconnectionForAndroidAuto; import android.annotation.CallbackExecutor; import android.annotation.StringRes; @@ -82,6 +83,8 @@ import java.util.stream.Stream; */ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private static final String TAG = "CachedBluetoothDevice"; + private static final ParcelUuid ANDROID_AUTO_UUID = + ParcelUuid.fromString("4de17a00-52cb-11e6-bdf4-0800200c9a66"); // See mConnectAttempted private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000; @@ -260,18 +263,26 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (mHandler.hasMessages(profile.getProfileId())) { mHandler.removeMessages(profile.getProfileId()); if (profile.getConnectionPolicy(mDevice) > - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - /* - * If we received state DISCONNECTED and previous state was - * CONNECTING and connection policy is FORBIDDEN or UNKNOWN - * then it's not really a failure to connect. - * - * Connection profile is considered as failed when connection - * policy indicates that profile should be connected - * but it got disconnected. - */ - Log.w(TAG, "onProfileStateChanged(): Failed to connect profile"); - setProfileConnectedStatus(profile.getProfileId(), true); + BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { + if (ignoreA2dpDisconnectionForAndroidAuto() + && profile instanceof A2dpProfile && isAndroidAuto()) { + Log.w(TAG, + "onProfileStateChanged(): Skip setting A2DP " + + "connection fail for Android Auto"); + } else { + /* + * If we received state DISCONNECTED and previous state was + * CONNECTING and connection policy is FORBIDDEN or UNKNOWN + * then it's not really a failure to connect. + * + * Connection profile is considered as failed when connection + * policy indicates that profile should be connected + * but it got disconnected. + */ + Log.w(TAG, + "onProfileStateChanged(): Failed to connect profile"); + setProfileConnectedStatus(profile.getProfileId(), true); + } } } break; @@ -2031,4 +2042,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void setLocalBluetoothManager(LocalBluetoothManager bluetoothManager) { mBluetoothManager = bluetoothManager; } + + private boolean isAndroidAuto() { + try { + ParcelUuid[] uuids = mDevice.getUuids(); + if (ArrayUtils.contains(uuids, ANDROID_AUTO_UUID)) { + return true; + } + } catch (RuntimeException e) { + Log.w(TAG, "Fail to check isAndroidAuto for " + this); + } + return false; + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java index 76aa5bf3334c..478a5d198239 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java @@ -80,8 +80,14 @@ public final class InputRouteManager { // behavior. @AudioDeviceType int deviceTypeToActivate = mSelectedInputDeviceType; for (AudioDeviceInfo info : addedDevices) { - if (InputMediaDevice.isSupportedInputDevice(info.getType())) { - deviceTypeToActivate = info.getType(); + @AudioDeviceType int type = info.getType(); + // Since onAudioDevicesAdded is called not only when new device is hot + // plugged, but also when the switcher dialog is opened, make sure to check + // against existing device list and only activate if the device does not + // exist previously. + if (InputMediaDevice.isSupportedInputDevice(type) + && findDeviceByType(type) == null) { + deviceTypeToActivate = type; } } @@ -140,16 +146,22 @@ public final class InputRouteManager { } // TODO(b/355684672): handle edge case where there are two devices with the same type. Only - // using a single mSelectedInputDeviceType might not be enough to recognize the correct device. - public @Nullable MediaDevice getSelectedInputDevice() { + // using a single type might not be enough to recognize the correct device. + @Nullable + private MediaDevice findDeviceByType(@AudioDeviceType int type) { for (MediaDevice device : mInputMediaDevices) { - if (((InputMediaDevice) device).getAudioDeviceInfoType() == mSelectedInputDeviceType) { + if (((InputMediaDevice) device).getAudioDeviceInfoType() == type) { return device; } } return null; } + @Nullable + public MediaDevice getSelectedInputDevice() { + return findDeviceByType(mSelectedInputDeviceType); + } + private void applyDefaultSelectedTypeToAllPresets() { mSelectedInputDeviceType = retrieveDefaultSelectedDeviceType(); AudioDeviceAttributes deviceAttributes = diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java index d808a25ebc04..9c34946f0c1b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java @@ -361,6 +361,26 @@ public class InputRouteManagerTest { } @Test + public void onAudioDevicesAdded_doNotActivatePreexistingDevice() { + final AudioManager audioManager = mock(AudioManager.class); + InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); + + final AudioDeviceInfo info = mockWiredHeadsetInfo(); + InputMediaDevice device = createInputMediaDeviceFromDeviceInfo(info); + inputRouteManager.mInputMediaDevices.add(device); + + // Trigger onAudioDevicesAdded with a device that already exists in the device list. + AudioDeviceInfo[] devices = {info}; + inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); + + // The device should not be activated. + for (@MediaRecorder.Source int preset : PRESETS) { + verify(audioManager, never()) + .setPreferredDeviceForCapturePreset(preset, getWiredHeadsetDeviceAttributes()); + } + } + + @Test public void onAudioDevicesRemoved_shouldApplyDefaultSelectedDeviceToAllPresets() { final AudioManager audioManager = mock(AudioManager.class); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index baf829ab3b14..fa6e2dbe02f3 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" /> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt index 558c1eba2c1c..65cd3c79cd16 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt @@ -397,6 +397,10 @@ constructor( ghostedView.visibility = View.VISIBLE ghostedView.invalidate() } + + if (isEphemeral) { + onDispose() + } } companion object { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 3926b326dacd..a17a1d46554f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -23,12 +23,17 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntRect +import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.android.compose.animation.scene.SceneScope import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection import com.android.systemui.communal.ui.compose.section.CommunalPopupSection +import com.android.systemui.communal.ui.compose.section.CommunalToDreamButtonSection import com.android.systemui.communal.ui.view.layout.sections.CommunalAppWidgetSection import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines @@ -49,6 +54,7 @@ constructor( private val ambientStatusBarSection: AmbientStatusBarSection, private val communalPopupSection: CommunalPopupSection, private val widgetSection: CommunalAppWidgetSection, + private val communalToDreamButtonSection: CommunalToDreamButtonSection, ) { @Composable @@ -82,11 +88,13 @@ constructor( Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth() ) } + with(communalToDreamButtonSection) { Button() } }, ) { measurables, constraints -> val communalGridMeasurable = measurables[0] val lockIconMeasurable = measurables[1] val bottomAreaMeasurable = measurables[2] + val screensaverButtonMeasurable: Measurable? = measurables.getOrNull(3) val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0) @@ -101,6 +109,15 @@ constructor( val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) + val screensaverButtonSizeInt = screensaverButtonSize.roundToPx() + val screensaverButtonPlaceable = + screensaverButtonMeasurable?.measure( + Constraints.fixed( + width = screensaverButtonSizeInt, + height = screensaverButtonSizeInt, + ) + ) + val communalGridPlaceable = communalGridMeasurable.measure( noMinConstraints.copy(maxHeight = lockIconBounds.top) @@ -109,12 +126,22 @@ constructor( layout(constraints.maxWidth, constraints.maxHeight) { communalGridPlaceable.place(x = 0, y = 0) lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top) - bottomAreaPlaceable.place( - x = 0, - y = constraints.maxHeight - bottomAreaPlaceable.height, + + val bottomAreaTop = constraints.maxHeight - bottomAreaPlaceable.height + bottomAreaPlaceable.place(x = 0, y = bottomAreaTop) + screensaverButtonPlaceable?.place( + x = + constraints.maxWidth - + screensaverButtonSizeInt - + Dimensions.ItemSpacing.roundToPx(), + y = lockIconBounds.top, ) } } } } + + companion object { + val screensaverButtonSize: Dp = 64.dp + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 573e5ca5e2d5..6a9dfbd29092 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 @@ -834,8 +835,16 @@ private fun BoxScope.CommunalHubLazyGrid( gridState = gridState, contentPadding = contentPadding, ) { 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)) }, @@ -1193,6 +1202,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()) } } 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/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index f1da01fef72c..4410e157b526 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -771,7 +771,7 @@ class ElementTest { private fun expectedOffset(currentOffset: Dp, density: Density): Dp { return with(density) { - OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + OffsetOverscrollEffect.computeOffset(density, currentOffset.toPx()).toDp() } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt index d267cc5c237f..da8fe3094448 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.properties.Delegates import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -44,165 +45,131 @@ import org.junit.runner.RunWith class OffsetOverscrollEffectTest { @get:Rule val rule = createComposeRule() - private fun expectedOffset(currentOffset: Dp, density: Density): Dp { - return with(density) { - OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + private val BOX_TAG = "box" + + private data class LayoutInfo(val layoutSize: Dp, val touchSlop: Float, val density: Density) { + fun expectedOffset(currentOffset: Dp): Dp { + return with(density) { + OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + } } } - @Test - fun applyVerticalOffset_duringVerticalOverscroll() { + private fun setupOverscrollableBox( + scrollableOrientation: Orientation, + overscrollEffectOrientation: Orientation = scrollableOrientation, + ): LayoutInfo { + val layoutSize: Dp = 200.dp + var touchSlop: Float by Delegates.notNull() // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. - var touchSlop = 0f lateinit var density: Density - val layoutSize = 200.dp - rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) + val overscrollEffect = rememberOffsetOverscrollEffect(overscrollEffectOrientation) Box( Modifier.overscroll(overscrollEffect) // A scrollable that does not consume the scroll gesture. .scrollable( state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, + orientation = scrollableOrientation, overscrollEffect = overscrollEffect, ) .size(layoutSize) - .testTag("box") + .testTag(BOX_TAG) ) } + return LayoutInfo(layoutSize, touchSlop, density) + } - val onBox = rule.onNodeWithTag("box") + @Test + fun applyVerticalOffset_duringVerticalOverscroll() { + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) } @Test fun applyNoOffset_duringHorizontalOverscroll() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - val layoutSize = 200.dp - - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Horizontal, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") + val info = + setupOverscrollableBox( + scrollableOrientation = Orientation.Vertical, + overscrollEffectOrientation = Orientation.Horizontal, ) - } - val onBox = rule.onNodeWithTag("box") - - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(touchSlop + layoutSize.toPx(), 0f), delayMillis = 1_000) + moveBy(Offset(info.touchSlop + info.layoutSize.toPx(), 0f), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) } @Test fun backToZero_afterOverscroll() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - lateinit var density: Density - val layoutSize = 200.dp - - rule.setContent { - density = LocalDensity.current - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") - ) - } - - val onBox = rule.onNodeWithTag("box") + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) rule.onRoot().performTouchInput { up() } - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) } @Test fun offsetOverscroll_followTheTouchPointer() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - lateinit var density: Density - val layoutSize = 200.dp - - rule.setContent { - density = LocalDensity.current - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") - ) - } - - val onBox = rule.onNodeWithTag("box") + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) + // First gesture, drag down. rule.onRoot().performTouchInput { down(center) // A full screen scroll. - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) rule.onRoot().performTouchInput { // Reduced by half. - moveBy(Offset(0f, -layoutSize.toPx() / 2), delayMillis = 1_000) + moveBy(Offset(0f, -info.layoutSize.toPx() / 2), delayMillis = 1_000) + } + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize / 2)) + + rule.onRoot().performTouchInput { up() } + // Animate back to 0. + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + + // Second gesture, drag up. + rule.onRoot().performTouchInput { + down(center) + // A full screen scroll. + moveBy(Offset(0f, -info.touchSlop - info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize / 2, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(-info.layoutSize)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt new file mode 100644 index 000000000000..88206850eb60 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.platform.test.annotations.EnableFlags +import android.service.dream.dreamManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED +import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.lifecycle.activateIn +import com.android.systemui.statusbar.policy.batteryController +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +@SmallTest +@EnableFlags(FLAG_GLANCEABLE_HUB_V2) +@RunWith(AndroidJUnit4::class) +class CommunalToDreamButtonViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest: CommunalToDreamButtonViewModel by lazy { + kosmos.communalToDreamButtonViewModel + } + + @Before + fun setUp() { + kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + underTest.activateIn(testScope) + } + + @Test + fun shouldShowDreamButtonOnHub_trueWhenCanDream() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(true) + whenever(batteryController.isPluggedIn()).thenReturn(true) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isTrue() + } + } + + @Test + fun shouldShowDreamButtonOnHub_falseWhenCannotDream() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(false) + whenever(batteryController.isPluggedIn()).thenReturn(true) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isFalse() + } + } + + @Test + fun shouldShowDreamButtonOnHub_falseWhenNotPluggedIn() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(true) + whenever(batteryController.isPluggedIn()).thenReturn(false) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isFalse() + } + } + + @Test + fun onShowDreamButtonTap_startsDream() = + with(kosmos) { + runTest { + underTest.onShowDreamButtonTap() + runCurrent() + + verify(dreamManager).startDream() + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt new file mode 100644 index 000000000000..b0f48038877e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.util + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize +import com.android.systemui.communal.util.ResizeUtils.resizeOngoingItems +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ResizeUtilsTest : SysuiTestCase() { + private val mockWidget = + mock<CommunalContentModel.WidgetContent.Widget> { + on { size } doReturn CommunalContentSize.Responsive(1) + } + + @Test + fun noOngoingContent() { + val list = listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized).containsExactly(mockWidget) + } + + @Test + fun singleOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly(CommunalContentSize.Responsive(1), mockWidget.size) + .inOrder() + } + + @Test + fun singleOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly(CommunalContentSize.Responsive(2), mockWidget.size) + .inOrder() + } + + @Test + fun singleOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + // A spacer should be added as the second element to avoid mixing widget content + // with ongoing content. + assertThat(resized[1]).isInstanceOf(CommunalContentModel.Spacer::class.java) + } + + @Test + fun twoOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun twoOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun twoOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + private fun createOngoingListWithSize(size: Int): List<CommunalContentModel.Ongoing> { + return List(size) { CommunalContentModel.Umo(createdTimestampMillis = 100) } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt index 68798a88eecc..9e7befd3cf92 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt @@ -27,15 +27,28 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.service.notification.StatusBarNotification import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.keyguardUpdateMonitor import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING import com.android.systemui.SysuiTestCase +import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.andSceneContainer +import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFaceAuthRepository +import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.fakeStatusBarStateController import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.RankingBuilder import com.android.systemui.statusbar.StatusBarState @@ -60,11 +73,16 @@ import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionCont import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -86,6 +104,8 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC statusBarStateController = fakeStatusBarStateController } + val testScope = kosmos.testScope + val dynamicPrivacyController: DynamicPrivacyController = kosmos.mockDynamicPrivacyController val lockscreenUserManager: NotificationLockscreenUserManager = kosmos.notificationLockscreenUserManager @@ -95,7 +115,12 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC kosmos.fakeStatusBarStateController val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController = kosmos.mockSensitiveNotificationProtectionController - val sceneInteractor: SceneInteractor = kosmos.sceneInteractor + val deviceEntryInteractor: DeviceEntryInteractor + get() = kosmos.deviceEntryInteractor + + val faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository + val sceneInteractor: SceneInteractor + get() = kosmos.sceneInteractor val coordinator: SensitiveContentCoordinator by lazy { kosmos.sensitiveContentCoordinator } @@ -112,592 +137,696 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC } @Test - fun onDynamicPrivacyChanged_invokeInvalidationListener() { - coordinator.attach(pipeline) - val invalidator = - withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } - val dynamicPrivacyListener = - withArgCaptor<DynamicPrivacyController.Listener> { - verify(dynamicPrivacyController).addListener(capture()) - } - - val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() - invalidator.setInvalidationListener(invalidationListener) - - dynamicPrivacyListener.onDynamicPrivacyChanged() + @EnableSceneContainer + fun onLockscreenDynamicallyUnlocked_invokeInvalidationListener() = + testScope.runTest { + // Setup + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + // Given the lockscreen is shown + setupLockScreen(canSwipeUp = false) + clearInvocations(invalidationListener) + + // When the device gets unlocked + faceAuthRepository.isAuthenticated.value = true + runCurrent() + + // Then the invalidationListener is called + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) - } + @Test + @DisableSceneContainer + fun onDynamicPrivacyChanged_invokeInvalidationListener() = + testScope.runTest { + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val dynamicPrivacyListener = + withArgCaptor<DynamicPrivacyController.Listener> { + verify(dynamicPrivacyController).addListener(capture()) + } + + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + dynamicPrivacyListener.onDynamicPrivacyChanged() + + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onSensitiveStateChanged_invokeInvalidationListener() { - coordinator.attach(pipeline) - val invalidator = - withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } - val onSensitiveStateChangedListener = - withArgCaptor<Runnable> { - verify(sensitiveNotificationProtectionController) - .registerSensitiveStateListener(capture()) - } - - val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() - invalidator.setInvalidationListener(invalidationListener) - - onSensitiveStateChangedListener.run() - - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) - } + fun onSensitiveStateChanged_invokeInvalidationListener() = + testScope.runTest { + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val onSensitiveStateChangedListener = + withArgCaptor<Runnable> { + verify(sensitiveNotificationProtectionController) + .registerSensitiveStateListener(capture()) + } + + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + onSensitiveStateChangedListener.run() + + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } @Test @DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_flagDisabled_filterNoAdded() { - coordinator.attach(pipeline) + fun screenshareSecretFilter_flagDisabled_filterNoAdded() = + testScope.runTest { + coordinator.attach(pipeline) - verify(pipeline, never()).addFinalizeFilter(any()) - } + verify(pipeline, never()).addFinalizeFilter(any()) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_sensitiveInctive_noFiltersSecret() { - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(false) - - coordinator.attach(pipeline) - val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } - - val defaultNotification = createNotificationEntry("test", false, false) - val notificationWithSecretVisibility = createNotificationEntry("test", true, false) - val notificationOnSecretChannel = createNotificationEntry("test", false, true) - - assertFalse(filter.shouldFilterOut(defaultNotification, 0)) - assertFalse(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) - assertFalse(filter.shouldFilterOut(notificationOnSecretChannel, 0)) - } + fun screenshareSecretFilter_sensitiveInctive_noFiltersSecret() = + testScope.runTest { + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(false) + + coordinator.attach(pipeline) + val filter = + withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } + + val defaultNotification = createNotificationEntry("test", false, false) + val notificationWithSecretVisibility = createNotificationEntry("test", true, false) + val notificationOnSecretChannel = createNotificationEntry("test", false, true) + + assertFalse(filter.shouldFilterOut(defaultNotification, 0)) + assertFalse(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) + assertFalse(filter.shouldFilterOut(notificationOnSecretChannel, 0)) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_sensitiveActive_filtersSecret() { - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - coordinator.attach(pipeline) - val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } - - val defaultNotification = createNotificationEntry("test", false, false) - val notificationWithSecretVisibility = createNotificationEntry("test", true, false) - val notificationOnSecretChannel = createNotificationEntry("test", false, true) - - assertFalse(filter.shouldFilterOut(defaultNotification, 0)) - assertTrue(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) - assertTrue(filter.shouldFilterOut(notificationOnSecretChannel, 0)) - } + fun screenshareSecretFilter_sensitiveActive_filtersSecret() = + testScope.runTest { + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + coordinator.attach(pipeline) + val filter = + withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } + + val defaultNotification = createNotificationEntry("test", false, false) + val notificationWithSecretVisibility = createNotificationEntry("test", true, false) + val notificationOnSecretChannel = createNotificationEntry("test", false, true) + + assertFalse(filter.shouldFilterOut(defaultNotification, 0)) + assertTrue(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) + assertTrue(filter.shouldFilterOut(notificationOnSecretChannel, 0)) + } @Test - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - } + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - } + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any())) + .thenReturn(true) + val entry = fakeNotification(2, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + whenever(sensitiveNotificationProtectionController.shouldProtectNotification(any())) + .thenReturn(true) + statusBarStateController.state = StatusBarState.KEYGUARD + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!, never()).setSensitive(any(), any()) + verify(entry.representativeEntry!!.row!!, never()).setPublicExpanderVisible(any()) + } + + private fun TestScope.setupLockScreen(canSwipeUp: Boolean) { + if (SceneContainerFlag.isEnabled) { + val authMethod = + if (canSwipeUp) AuthenticationMethodModel.None + else AuthenticationMethodModel.Password + kosmos.fakeAuthenticationRepository.setAuthenticationMethod(authMethod) + kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) + switchToScene(Scenes.Lockscreen) + } else { + whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(canSwipeUp) + } + } - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any())) - .thenReturn(true) - val entry = fakeNotification(2, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - whenever(sensitiveNotificationProtectionController.shouldProtectNotification(any())) - .thenReturn(true) - statusBarStateController.state = StatusBarState.KEYGUARD - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!, never()).setSensitive(any(), any()) - verify(entry.representativeEntry!!.row!!, never()).setPublicExpanderVisible(any()) + private fun TestScope.switchToScene(sceneKey: SceneKey) { + sceneInteractor.changeScene(sceneKey, "reason") + sceneInteractor.setTransitionState(flowOf(ObservableTransitionState.Idle(sceneKey))) + runCurrent() } private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt index c0a206afe64b..9ad23154c334 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt @@ -49,11 +49,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { private val dispatcher = StandardTestDispatcher() private val testScope = TestScope(dispatcher) - private val iconsInteractor = - FakeMobileIconsInteractor( - FakeMobileMappingsProxy(), - mock(), - ) + private val iconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock()) private val repo = FakeDeviceBasedSatelliteRepository() private val connectivityRepository = FakeConnectivityRepository() @@ -515,7 +511,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // GIVEN, 2 connection val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) - val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) // WHEN all connections are NOT OOS. i1.isInService.value = true @@ -547,7 +543,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // GIVEN a condition that should return true (all conections OOS) val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) - val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) i1.isInService.value = true i2.isInService.value = true @@ -579,4 +575,40 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // THEN the interactor returns true due to the wifi network being active assertThat(latest).isTrue() } + + @Test + @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun isAnyConnectionNtn_trueWhenAnyNtn() = + testScope.runTest { + val latest by collectLastValue(underTest.isAnyConnectionNtn) + + // GIVEN, 2 connection + val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) + + // WHEN at least one connection is using ntn + i1.isNonTerrestrial.value = true + i2.isNonTerrestrial.value = false + + // THEN the value is propagated to this interactor + assertThat(latest).isTrue() + } + + @Test + @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun isAnyConnectionNtn_falseWhenNoNtn() = + testScope.runTest { + val latest by collectLastValue(underTest.isAnyConnectionNtn) + + // GIVEN, 2 connection + val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) + + // WHEN at no connection is using ntn + i1.isNonTerrestrial.value = false + i2.isNonTerrestrial.value = false + + // THEN the value is propagated to this interactor + assertThat(latest).isFalse() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt index 509aa7ad67fd..fe5b56a4e66d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt @@ -327,10 +327,11 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN satellite is allowed repo.isSatelliteAllowedForCurrentLocation.value = true - // GIVEN all icons are OOS + // GIVEN all icons are OOS and not ntn val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false i1.isEmergencyOnly.value = false + i1.isNonTerrestrial.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) @@ -344,6 +345,29 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { } @Test + fun icon_nullWhenConnected_mobileNtnConnectionExists() = + testScope.runTest { + val latest by collectLastValue(underTest.icon) + + // GIVEN satellite is allowed + repo.isSatelliteAllowedForCurrentLocation.value = true + + // GIVEN ntn connection exists + val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) + i1.isNonTerrestrial.value = true + + // GIVEN apm is disabled + airplaneModeRepository.setIsAirplaneMode(false) + + // GIVEN satellite reports that it is Connected + repo.connectionState.value = SatelliteConnectionState.On + + // THEN icon is null because despite being connected, the mobile stack is reporting a + // nonTerrestrial network, and therefore will have its own icon + assertThat(latest).isNull() + } + + @Test fun icon_satelliteIsProvisioned() = testScope.runTest { val latest by collectLastValue(underTest.icon) diff --git a/packages/SystemUI/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/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 658f2c27b4cb..49ac145d33cc 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/> diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index f9b30c6c2ba1..ea428698e476 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -27,6 +27,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey +import com.android.systemui.Flags.communalResponsiveGrid import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.communal.data.repository.CommunalMediaRepository import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository @@ -535,7 +536,9 @@ constructor( // Order by creation time descending. ongoingContent.sortByDescending { it.createdTimestampMillis } // Resize the items. - ongoingContent.resizeItems() + if (!communalResponsiveGrid()) { + ongoingContent.resizeItems() + } // Return the sorted and resized items. ongoingContent diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt index da613f58dce8..c0456d5bb46e 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt @@ -110,6 +110,11 @@ sealed interface CommunalContentModel { get() = fixedHalfOrResponsiveSize() } + /** An empty spacer to reserve space in the grid. */ + data class Spacer(override val size: CommunalContentSize) : CommunalContentModel { + override val key: String = KEY.spacer() + } + /** A CTA tile in the glanceable hub view mode which can be dismissed. */ class CtaTileInViewMode : CommunalContentModel { override val key: String = KEY.CTA_TILE_IN_VIEW_MODE_KEY @@ -171,6 +176,10 @@ sealed interface CommunalContentModel { fun umo(): String { return "umo" } + + fun spacer(): String { + return "spacer_${UUID.randomUUID()}" + } } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt new file mode 100644 index 000000000000..7d5b196dfaa8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.annotation.SuppressLint +import android.app.DreamManager +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.util.kotlin.isDevicePluggedIn +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class CommunalToDreamButtonViewModel +@AssistedInject +constructor( + @Background private val backgroundContext: CoroutineContext, + batteryController: BatteryController, + private val dreamManager: DreamManager, +) : ExclusiveActivatable() { + + private val _requests = Channel<Unit>(Channel.BUFFERED) + + /** Whether we should show a button on hub to switch to dream. */ + @SuppressLint("MissingPermission") + val shouldShowDreamButtonOnHub = + batteryController + .isDevicePluggedIn() + .distinctUntilChanged() + .map { isPluggedIn -> isPluggedIn && dreamManager.canStartDreaming(true) } + .flowOn(backgroundContext) + + /** Handle a tap on the "show dream" button. */ + fun onShowDreamButtonTap() { + _requests.trySend(Unit) + } + + @SuppressLint("MissingPermission") + override suspend fun onActivated(): Nothing = coroutineScope { + launch { + _requests.receiveAsFlow().collectLatest { + withContext(backgroundContext) { dreamManager.startDream() } + } + } + + awaitCancellation() + } + + @AssistedFactory + interface Factory { + fun create(): CommunalToDreamButtonViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt b/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt new file mode 100644 index 000000000000..36cc1c051336 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.util + +import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize + +object ResizeUtils { + /** + * Resizes ongoing items such that we don't mix regular content with ongoing content. + * + * NOTE: This is *NOT* a pure function, as it modifies items in the input list. + * + * Assumptions: + * 1. Ongoing content is always at the start of the list. + * 2. The maximum size of ongoing content is 2 rows. + */ + fun resizeOngoingItems( + list: List<CommunalContentModel>, + numRows: Int, + ): List<CommunalContentModel> { + val finalizedList = mutableListOf<CommunalContentModel>() + val numOngoing = list.count { it is CommunalContentModel.Ongoing } + // Calculate the number of extra rows we have if each ongoing item were to take up a single + // row. This is the number of rows we have to distribute across items. + var extraRows = + if (numOngoing % numRows == 0) { + 0 + } else { + numRows - (numOngoing % numRows) + } + var remainingRows = numRows + + for (item in list) { + if (item is CommunalContentModel.Ongoing) { + if (remainingRows == 0) { + // Start a new column. + remainingRows = numRows + } + val newSize = if (extraRows > 0 && remainingRows > 1) 2 else 1 + item.size = CommunalContentSize.Responsive(newSize) + finalizedList.add(item) + extraRows -= (newSize - 1) + remainingRows -= newSize + } else { + if (numOngoing > 0 && remainingRows > 0) { + finalizedList.add( + CommunalContentModel.Spacer(CommunalContentSize.Responsive(remainingRows)) + ) + } + remainingRows = -1 + finalizedList.add(item) + } + } + return finalizedList + } +} diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 2fda2013d6f5..d33ad8f80021 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -122,21 +122,20 @@ public class MediaProjectionPermissionActivity extends Activity { final Intent launchingIntent = getIntent(); mReviewGrantedConsentRequired = launchingIntent.getBooleanExtra( EXTRA_USER_REVIEW_GRANTED_CONSENT, false); - if (com.android.systemui.Flags.mediaProjectionRequestAttributionFix()) { - mPackageName = getLaunchedFromPackage(); - } else { - mPackageName = getCallingPackage(); - } - // This activity is launched directly by an app, or system server. System server provides - // the package name through the intent if so. - if (mPackageName == null || ( - com.android.systemui.Flags.mediaProjectionRequestAttributionFix() - && getCallingPackage() == null)) { + // The original requester of this activity start + mPackageName = getLaunchedFromPackage(); + + // This activity is launched directly by using startActivity(), + // thus getCallingPackage() will be null. + if (getCallingPackage() == null) { + // System server provides the package name through the intent if so and is able to get + // the result back. Other applications can't. if (launchingIntent.hasExtra(EXTRA_PACKAGE_REUSING_GRANTED_CONSENT)) { mPackageName = launchingIntent.getStringExtra( EXTRA_PACKAGE_REUSING_GRANTED_CONSENT); } else { + // The activity was not launched for result, we abort here finishAsCancelled(); return; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt index ead38f3f9b52..ef45ae76c20c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt @@ -209,7 +209,7 @@ constructor( // TODO(b/250618218): Remove this method once we know the root cause of b/250618218. fun logTileBackgroundColorUpdateIfInternetTile( - tileSpec: String, + tileSpec: String?, state: Int, disabledByPolicy: Boolean, color: Int, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt index fdb15b9c2615..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 @@ -30,11 +30,6 @@ import com.android.systemui.qs.tiles.dialog.WifiStateWorker import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.statusbar.connectivity.AccessPointController -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.stateIn import javax.inject.Inject import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.withContext diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt index ef7b1c3d562e..04458f3a7168 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt @@ -14,10 +14,13 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification import android.os.UserHandle +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.KeyguardUpdateMonitor import com.android.server.notification.Flags.screenshareNotificationHiding import com.android.systemui.dagger.qualifiers.Application @@ -44,9 +47,9 @@ import dagger.Binds import dagger.Module import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapNotNull -import com.android.app.tracing.coroutines.launchTraced as launch @Module(includes = [PrivateSensitiveContentCoordinatorModule::class]) interface SensitiveContentCoordinatorModule @@ -80,6 +83,7 @@ constructor( DynamicPrivacyController.Listener, OnBeforeRenderListListener { private var inTransitionFromLockedToGone = false + private var canSwipeToEnter = false private val onSensitiveStateChanged = Runnable() { invalidateList("onSensitiveStateChanged") } @@ -98,7 +102,9 @@ constructor( } override fun attach(pipeline: NotifPipeline) { - dynamicPrivacyController.addListener(this) + if (!SceneContainerFlag.isEnabled) { + dynamicPrivacyController.addListener(this) + } if (screenshareNotificationHiding()) { sensitiveNotificationProtectionController.registerSensitiveStateListener( onSensitiveStateChanged @@ -128,6 +134,15 @@ constructor( invalidateList("inTransitionFromLockedToGoneChanged") } } + scope.launch { + deviceEntryInteractor.canSwipeToEnter.collect { + val canSwipeToEnter = it ?: false + if (this@SensitiveContentCoordinatorImpl.canSwipeToEnter != canSwipeToEnter) { + this@SensitiveContentCoordinatorImpl.canSwipeToEnter = canSwipeToEnter + invalidateList("canSwipeToEnterChanged") + } + } + } } } @@ -168,7 +183,9 @@ constructor( (devicePublic && !lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)) || isSensitiveContentProtectionActive - val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked + val dynamicallyUnlocked = + if (SceneContainerFlag.isEnabled) canSwipeToEnter + else dynamicPrivacyController.isDynamicallyUnlocked for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) { val notifUserId = entry.sbn.user.identifier val userLockscreen = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index ba707a5cd0b1..245b1d29fb79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -429,9 +429,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { }; /** - * Recalculate sensitiveness without animation; called when waking up while keyguard occluded. + * Recalculate sensitiveness without animation; called when waking up while keyguard occluded, + * or whenever we update the Lockscreen public mode. */ - public void updateSensitivenessForOccludedWakeup() { + public void updateSensitivenessWithoutAnimation() { updateSensitivenessWithAnimation(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/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/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/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 6912eda3c3d4..d157cf2d51e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -36,8 +36,6 @@ import static com.android.systemui.statusbar.phone.CentralSurfaces.MSG_DISMISS_K import static com.google.common.truth.Truth.assertThat; -import static kotlinx.coroutines.flow.FlowKt.flowOf; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -56,6 +54,8 @@ import static org.mockito.Mockito.when; import static java.util.Collections.emptySet; +import static kotlinx.coroutines.flow.FlowKt.flowOf; + import android.app.ActivityManager; import android.app.IWallpaperManager; import android.app.NotificationManager; @@ -138,6 +138,7 @@ import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.qs.flags.QSComposeFragment; import com.android.systemui.res.R; import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor; import com.android.systemui.scene.domain.startable.ScrimStartable; @@ -181,6 +182,7 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.AvalancheProvider; import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider; @@ -198,7 +200,6 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.window.StatusBarWindowController; @@ -217,10 +218,6 @@ import com.android.systemui.volume.VolumeComponent; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.startingsurface.StartingSurface; -import dagger.Lazy; - -import kotlinx.coroutines.test.TestScope; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -237,6 +234,9 @@ import java.util.Set; import javax.inject.Provider; +import dagger.Lazy; +import kotlinx.coroutines.test.TestScope; + @SmallTest @RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) @@ -667,6 +667,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCentralSurfaces.startKeyguard(); mInitController.executePostInitTasks(); mCentralSurfaces.registerCallbacks(); + // Clear first invocations caused by registering flows with JavaAdapter + mTestScope.getTestScheduler().runCurrent(); + clearInvocations(mScrimController); } @Test @@ -1159,8 +1162,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test @EnableSceneContainer - public void brightnesShowingChanged_flagEnabled_ScrimControllerNotified() { - mCentralSurfaces.registerCallbacks(); + public void brightnesShowingChanged_sceneContainerFlagEnabled_ScrimControllerNotified() { final ScrimStartable scrimStartable = mKosmos.getScrimStartable(); scrimStartable.start(); @@ -1178,9 +1180,25 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test @DisableSceneContainer - public void brightnesShowingChanged_flagDisabled_ScrimControllerNotified() { - mCentralSurfaces.registerCallbacks(); + @EnableFlags(QSComposeFragment.FLAG_NAME) + public void brightnesShowingChanged_qsUiRefactorFlagEnabled_ScrimControllerNotified() { + mBrightnessMirrorShowingInteractor.setMirrorShowing(true); + mTestScope.getTestScheduler().runCurrent(); + verify(mScrimController, atLeastOnce()).legacyTransitionTo(ScrimState.BRIGHTNESS_MIRROR); + clearInvocations(mScrimController); + + mBrightnessMirrorShowingInteractor.setMirrorShowing(false); + mTestScope.getTestScheduler().runCurrent(); + ArgumentCaptor<ScrimState> captor = ArgumentCaptor.forClass(ScrimState.class); + // The default is to call the one with the callback argument + verify(mScrimController, atLeastOnce()).legacyTransitionTo(captor.capture(), any()); + assertThat(captor.getValue()).isNotEqualTo(ScrimState.BRIGHTNESS_MIRROR); + } + @Test + @DisableSceneContainer + @DisableFlags(QSComposeFragment.FLAG_NAME) + public void brightnesShowingChanged_flagsDisabled_ScrimControllerNotified() { mBrightnessMirrorShowingInteractor.setMirrorShowing(true); mTestScope.getTestScheduler().runCurrent(); verify(mScrimController, never()).legacyTransitionTo(ScrimState.BRIGHTNESS_MIRROR); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt new file mode 100644 index 000000000000..b407b1ba227a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.service.dream.dreamManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.statusbar.policy.batteryController + +val Kosmos.communalToDreamButtonViewModel by + Kosmos.Fixture { + CommunalToDreamButtonViewModel( + backgroundContext = testDispatcher, + batteryController = batteryController, + dreamManager = dreamManager, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt index 4a249a8591e9..88bf9a5f2d5b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt @@ -42,6 +42,6 @@ var Kosmos.sensitiveContentCoordinator: SensitiveContentCoordinator by sensitiveNotificationProtectionController, deviceEntryInteractor, sceneInteractor, - testScope, + testScope.backgroundScope, ) } diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig index 5e1b1473d233..9c83757f4b0f 100644 --- a/services/autofill/bugfixes.aconfig +++ b/services/autofill/bugfixes.aconfig @@ -9,6 +9,16 @@ flag { } flag { + name: "improve_fill_dialog_aconfig" + namespace: "autofill" + description: "Improvements for Fill Dialog. Guard DeviceConfig rollout " + bug: "382493181" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fill_fields_from_current_session_only" namespace: "autofill" description: "Only fill autofill fields that are part of the current session." diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java index 219b788448e8..5e7e557d7041 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -354,6 +354,13 @@ final class AutofillInlineSuggestionsRequestSession { } } + private void handleOnInputMethodStartInputView() { + synchronized (mLock) { + mUiCallback.onInputMethodStartInputView(); + handleOnReceiveImeStatusUpdated(true, true); + } + } + /** * Handles the IME session status received from the IME. * @@ -437,8 +444,8 @@ final class AutofillInlineSuggestionsRequestSession { final AutofillInlineSuggestionsRequestSession session = mSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( - AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, - session, true, true)); + AutofillInlineSuggestionsRequestSession::handleOnInputMethodStartInputView, + session)); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 259ea148f163..cba8c66cd5e3 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -2139,6 +2139,32 @@ public final class AutofillManagerService } @Override + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationStart(sessionId, startTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationStart(): no service for " + userId); + } + } + } + + @Override + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationEnd(sessionId, endTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationEnd(): no service for " + userId); + } + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 5cf96bfb2b8b..0fa43ac7091b 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -823,6 +823,36 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationStart(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationStart(startTimeMs); + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationEnd(endTimeMs); + } + + @GuardedBy("mLock") @Override // from PerUserSystemService protected void handlePackageUpdateLocked(@NonNull String packageName) { final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6b227d7a876e..9c6e4741730a 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -40,6 +40,7 @@ import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; import static android.service.autofill.Flags.highlightAutofillSingleField; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED; import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; @@ -50,6 +51,7 @@ import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN; import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID; import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; + import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_EXPLICITLY_REQUESTED; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER; @@ -184,6 +186,7 @@ import android.view.autofill.IAutoFillManagerClient; import android.view.autofill.IAutofillWindowPresenter; import android.view.inputmethod.InlineSuggestionsRequest; import android.widget.RemoteViews; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; @@ -195,6 +198,7 @@ import com.android.server.autofill.ui.InlineFillUi; import com.android.server.autofill.ui.PendingUi; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -248,6 +252,8 @@ final class Session private static final int DEFAULT__FILL_REQUEST_ID_SNAPSHOT = -2; private static final int DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT = -2; + private static final long DEFAULT_UNASSIGNED_TIME = -1; + static final String SESSION_ID_KEY = "autofill_session_id"; static final String REQUEST_ID_KEY = "autofill_request_id"; @@ -292,6 +298,31 @@ final class Session @Retention(RetentionPolicy.SOURCE) @interface SessionState {} + /** + * Indicates fill dialog will not be shown. + */ + private static final int SHOW_FILL_DIALOG_NO = 0; + + /** + * Indicates fill dialog is shown. + */ + private static final int SHOW_FILL_DIALOG_YES = 1; + + /** + * Indicates fill dialog can be shown, but we need to wait. + * For eg, if the IME animation is happening, we need for it to complete before fill dialog can + * be shown. + */ + private static final int SHOW_FILL_DIALOG_WAIT = 2; + + @IntDef(prefix = { "SHOW_FILL_DIALOG_" }, value = { + SHOW_FILL_DIALOG_NO, + SHOW_FILL_DIALOG_YES, + SHOW_FILL_DIALOG_WAIT + }) + @Retention(RetentionPolicy.SOURCE) + private @interface ShowFillDialogState{} + @GuardedBy("mLock") private final SessionFlags mSessionFlags; @@ -576,6 +607,47 @@ final class Session private boolean mIgnoreViewStateResetToEmpty; + /** + * Whether improveFillDialog feature is enabled or not. + * Configured via device config flag and aconfig flag. + */ + private final boolean mImproveFillDialogEnabled; + + /** + * Timeout, after which, fill dialog won't be shown. + * Configured via device config flag. + */ + private final long mFillDialogTimeoutMs; + + /** + * Time to wait after ime Animation ends before showing up fill dialog. + * Configured via device config flag. + */ + private final long mFillDialogMinWaitAfterImeAnimationMs; + + /** + * Indicates the need to wait for ime animation to end before showing up fill dialog. + * This is set when we receive notification of ime animation start. + * Focussing on one input field from another wouldn't cause ime to re-animate. So this will let + * us know whether we need to wait for ime animation finish notification. + */ + private boolean mWaitForImeAnimation; + + /** + * A runnable set to run when there is a need to wait for ime animation to end before showing + * up fill dialog. This is set only if the fill response has been received, and the response + * is eligible for showing up fill dialog, but the ime animation hasn't completed. This allows + * for this runnable to be scheduled/run when the ime animation ends, in order to show fill + * dialog. + */ + private Runnable mFillDialogRunnable; + + private long mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + /* * Id of the previous view that was entered. Once set, it would only be replaced by non-null * view ids. @@ -1493,6 +1565,12 @@ final class Session // Now request the assist structure data. requestAssistStructureLocked(requestId, flags); + if (mImproveFillDialogEnabled) { + // New request has been sent, so re-enable fill dialog. + // Fill dialog is eligible to be shown after each Fill request. + enableFillDialog(); + } + return Optional.of(requestId); } @@ -1657,6 +1735,11 @@ final class Session mSaveEventLogger = SaveEventLogger.forSessionId(sessionId, mLatencyBaseTime); mIsPrimaryCredential = isPrimaryCredential; mIgnoreViewStateResetToEmpty = AutofillFeatureFlags.shouldIgnoreViewStateResetToEmpty(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + mFillDialogTimeoutMs = AutofillFeatureFlags.getFillDialogTimeoutMs(); + mFillDialogMinWaitAfterImeAnimationMs = + AutofillFeatureFlags.getFillDialogMinWaitAfterImeAnimationtEndMs(); synchronized (mLock) { mSessionFlags = new SessionFlags(); @@ -1682,6 +1765,13 @@ final class Session public void notifyInlineUiHidden(AutofillId autofillId) { notifyFillUiHidden(autofillId); } + + @Override + public void onInputMethodStartInputView() { + // TODO(b/377868687): This method isn't called when IME doesn't + // support inline suggestion. Handle those cases as well. + onInputMethodStart(); + } }); mMetricsLogger.write( @@ -3044,6 +3134,12 @@ final class Session } } + private void onInputMethodStart() { + synchronized (mLock) { + mLastInputStartTime = SystemClock.elapsedRealtime(); + } + } + private void doStartIntentSender(IntentSender intentSender, Intent intent) { try { synchronized (mLock) { @@ -5407,6 +5503,15 @@ final class Session } } + private void resetImeAnimationState() { + synchronized (mLock) { + mWaitForImeAnimation = false; + mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + } + } + @Override public void onFillReady( @NonNull FillResponse response, @@ -5452,18 +5557,24 @@ final class Session final AutofillId[] ids = response.getFillDialogTriggerIds(); if (ids != null && ArrayUtils.contains(ids, filledId)) { - if (requestShowFillDialog(response, filledId, filterText, flags)) { + @ShowFillDialogState int fillDialogState = + requestShowFillDialog(response, filledId, filterText, flags); + if (fillDialogState == SHOW_FILL_DIALOG_YES) { synchronized (mLock) { final ViewState currentView = mViewStates.get(mCurrentViewId); currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN); } - // Just show fill dialog once, so disabled after shown. + // Just show fill dialog once per fill request, so disabled after shown. // Note: Cannot disable before requestShowFillDialog() because the method - // need to check whether fill dialog enabled. + // need to check whether fill dialog is enabled. setFillDialogDisabled(); + resetImeAnimationState(); return; - } else { + } else if (fillDialogState == SHOW_FILL_DIALOG_NO) { + resetImeAnimationState(); setFillDialogDisabled(); + } else { // SHOW_FILL_DIALOG_WAIT + return; } } @@ -5559,7 +5670,20 @@ final class Session } } + private void enableFillDialog() { + if (sVerbose) { + Slog.v(TAG, "Enabling Fill Dialog...."); + } + synchronized (mLock) { + mSessionFlags.mFillDialogDisabled = false; + } + notifyClientFillDialogTriggerIds(null); + } + private void setFillDialogDisabled() { + if (sVerbose) { + Slog.v(TAG, "Disabling Fill Dialog."); + } synchronized (mLock) { mSessionFlags.mFillDialogDisabled = true; } @@ -5577,24 +5701,28 @@ final class Session } } - private boolean requestShowFillDialog( + private @ShowFillDialogState int requestShowFillDialog( FillResponse response, AutofillId filledId, String filterText, int flags) { if (!isFillDialogUiEnabled()) { + // TODO(b/377868687): The above check includes credman fields. We may want to show + // credman fields again. // Unsupported fill dialog UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled"); - return false; + if (sDebug) Log.w(TAG, "requestShowFillDialog(): fill dialog is disabled"); + return SHOW_FILL_DIALOG_NO; } - if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { - // IME is showing, fallback to normal suggestions UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: IME is showing"); - return false; - } + if (!mImproveFillDialogEnabled) { + if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { + // IME is showing, fallback to normal suggestions UI + if (sDebug) Log.w(TAG, "requestShowFillDialog(): IME is showing"); + return SHOW_FILL_DIALOG_NO; + } - if (mInlineSessionController.isImeShowing()) { - // IME is showing, fallback to normal suggestions UI - // Note: only work when inline suggestions supported - return false; + if (mInlineSessionController.isImeShowing()) { + // IME is showing, fallback to normal suggestions UI + // Note: only work when inline suggestions supported + return SHOW_FILL_DIALOG_NO; + } } synchronized (mLock) { @@ -5602,29 +5730,84 @@ final class Session || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) { // Last fill dialog triggered ids are changed. if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed."); - return false; + return SHOW_FILL_DIALOG_NO; + } + + if (mImproveFillDialogEnabled && mInlineSessionController.isImeShowing()) { + long currentTimestampMs = SystemClock.elapsedRealtime(); + long durationMs = currentTimestampMs - mLastInputStartTime; + if (sVerbose) { + Log.d(TAG, "IME is showing. Checking for elapsed time "); + Log.d(TAG, "IME is showing. Timestamps start: " + mLastInputStartTime + + " current: " + currentTimestampMs + " duration: " + durationMs + + " mFillDialogTimeoutMs: " + mFillDialogTimeoutMs); + } + + // Following situations can arise wrt IME animation. + // 1. No animation happening (eg IME already animated). In that case, + // mWaitForImeAnimation should be false. This is possible if the IME is already up + // on a field, but the user focusses on another field. Under such condition, + // since IME has already animated, there won't be another animation. However, + // onInputStartInputView is still called. + // 2. Animation is still proceeding. We should wait for animation to finish, + // and then proceed. + // 3. Animation is complete. + if (mWaitForImeAnimation) { + // we need to wait for animation to happen. We can't return from here yet. + // This is the situation #2 described above. + Log.d(TAG, "Waiting for ime animation to complete before showing fill dialog"); + mFillDialogRunnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + return SHOW_FILL_DIALOG_WAIT; + } + + // Incorporate situations 1 & 3 discussed above. We calculate the duration from the + // max of start input time or the ime finish time + long effectiveDuration = currentTimestampMs + - Math.max(mLastInputStartTime, mImeAnimationFinishTimeMs); + if (effectiveDuration >= mFillDialogTimeoutMs) { + Log.d(TAG, "Fill dialog not shown since IME has been up for more time than " + + mFillDialogTimeoutMs + "ms"); + return SHOW_FILL_DIALOG_NO; + } else if (effectiveDuration < mFillDialogMinWaitAfterImeAnimationMs) { + // we need to wait for some time after animation ends + Runnable runnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + mHandler.postDelayed(runnable, + mFillDialogMinWaitAfterImeAnimationMs - effectiveDuration); + return SHOW_FILL_DIALOG_WAIT; + } } } + showFillDialog(response, filledId, filterText); + return SHOW_FILL_DIALOG_YES; + } + + private Runnable createFillDialogEvalRunnable( + @NonNull FillResponse response, + @NonNull AutofillId filledId, + String filterText, + int flags) { + return () -> { + synchronized (mLock) { + AutofillValue value = AutofillValue.forText(filterText); + onFillReady(response, filledId, value, flags); + } + }; + } + + private void showFillDialog(FillResponse response, AutofillId filledId, String filterText) { Drawable serviceIcon = null; + PresentationStatsEventLogger logger = null; synchronized (mLock) { serviceIcon = getServiceIcon(response); + logger = mPresentationStatsEventLogger; } - getUiForShowing() - .showFillDialog( - filledId, - response, - filterText, - mService.getServicePackageName(), - mComponentName, - serviceIcon, - this, - id, - mCompatMode, - mPresentationStatsEventLogger, - mLock); - return true; + getUiForShowing().showFillDialog(filledId, response, filterText, + mService.getServicePackageName(), mComponentName, serviceIcon, this, + id, mCompatMode, logger, mLock); } /** @@ -7689,6 +7872,30 @@ final class Session mSessionState = STATE_REMOVED; } + @GuardedBy("mLock") + public void notifyImeAnimationStart(long startTimeMs) { + mImeAnimationStartTimeMs = startTimeMs; + mWaitForImeAnimation = true; + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(long endTimeMs) { + mImeAnimationFinishTimeMs = endTimeMs; + // Make sure to use mRunnable with synchronized + if (mFillDialogRunnable != null) { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, starting fill dialog."); + } + mHandler.postDelayed(mFillDialogRunnable, mFillDialogMinWaitAfterImeAnimationMs); + mFillDialogRunnable = null; + } else { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, no runnable present."); + } + } + mWaitForImeAnimation = false; + } + void onPendingSaveUi(int operation, @NonNull IBinder token) { getUiForShowing().onPendingSaveUi(operation, token); } diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java index ffc80ee7d710..7287bdd8e34f 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java @@ -409,5 +409,10 @@ public final class InlineFillUi { * Callback to notify inline ui is hidden. */ void notifyInlineUiHidden(@NonNull AutofillId autofillId); + + /** + * Callback to notify input method started. + */ + void onInputMethodStartInputView(); } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index eba9a25717dd..bd7a0ac55117 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -449,6 +449,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private AtomicBoolean mIsSatelliteEnabled; private AtomicBoolean mWasSatelliteEnabledNotified; + private final int mPid = Process.myPid(); + /** * Per-phone map of precise data connection state. The key of the map is the pair of transport * type and APN setting. This is the cache to prevent redundant callbacks to the listeners. @@ -1441,7 +1443,17 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId)); + if (Flags.passCopiedCallStateList()) { + List<CallState> callList; + if (r.callerPid == mPid) { + callList = List.copyOf(mCallStateLists.get(r.phoneId)); + } else { + callList = mCallStateLists.get(r.phoneId); + } + r.callback.onCallStatesChanged(callList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId)); + } } catch (RemoteException ex) { remove(r.binder); } @@ -2573,12 +2585,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (notifyCallState) { + List<CallState> copyList = null; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { + // If listener is in the same process, original instance can be passed + // to the listener via AIDL without serialization/de-serialization. We + // will pass the copied list. Since the element is newly created instead + // of modification for the change, we can use shallow copy for this. try { - r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + if (Flags.passCopiedCallStateList()) { + if (r.callerPid == mPid && copyList == null) { + copyList = List.copyOf(mCallStateLists.get(phoneId)); + } + r.callback.onCallStatesChanged(copyList == null + ? mCallStateLists.get(phoneId) : copyList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2906,13 +2931,21 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("There is no active call to report CallQuality"); return; } - + List<CallState> copyList = null; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { try { - r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + if (Flags.passCopiedCallStateList()) { + if (r.callerPid == mPid && copyList == null) { + copyList = List.copyOf(mCallStateLists.get(phoneId)); + } + r.callback.onCallStatesChanged(copyList == null + ? mCallStateLists.get(phoneId) : copyList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index aea24d978bee..c27126a01a32 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1101,9 +1101,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub /** StatsPullAtomCallback for pulling BatteryUsageStats data. */ private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { - private static final long BATTERY_USAGE_STATS_PER_UID_MAX_STATS_AGE = - TimeUnit.HOURS.toMillis(2); - @Override public int onPullAtom(int atomTag, List<StatsEvent> data) { final BatteryUsageStats bus; @@ -1171,8 +1168,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub .setMinConsumedPowerThreshold(minConsumedPowerThreshold); if (isBatteryUsageStatsAccumulationSupported()) { - query.accumulated() - .setMaxStatsAgeMs(BATTERY_USAGE_STATS_PER_UID_MAX_STATS_AGE); + query.accumulated(); } bus = getBatteryUsageStats(List.of(query.build())).get(0); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 295e0443371d..06c586f5e9c2 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3191,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub { resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted, - "proxy " + message, shouldCollectMessage, 1); + "proxy " + message, shouldCollectMessage); if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag, proxiedPackageName); @@ -3210,20 +3210,7 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName, proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp, - message, shouldCollectMessage, 1); - } - - @Override - public void noteOperationsInBatch(Map batchedNoteOps) { - for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) { - AppOpsManager.NotedOp notedOp = entry.getKey(); - int notedCount = entry.getValue(); - mCheckOpsDelegateDispatcher.noteOperation( - notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(), - notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(), - notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(), - notedOp.getShouldCollectMessage(), notedCount); - } + message, shouldCollectMessage); } @Override @@ -3241,7 +3228,7 @@ public class AppOpsService extends IAppOpsService.Stub { } return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, 1); + shouldCollectMessage); } @Override @@ -3250,12 +3237,13 @@ public class AppOpsService extends IAppOpsService.Stub { String message, boolean shouldCollectMessage) { return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, 1); + shouldCollectMessage); } private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName, - @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount) { + @Nullable String attributionTag, int virtualDeviceId, + boolean shouldCollectAsyncNotedOp, @Nullable String message, + boolean shouldCollectMessage) { String resolvedPackageName; if (!shouldUseNewCheckOp()) { verifyIncomingUid(uid); @@ -3290,14 +3278,14 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag, virtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp, - message, shouldCollectMessage, notedCount); + message, shouldCollectMessage); } private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int virtualDeviceId, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { PackageVerificationResult pvr; try { pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); @@ -3400,11 +3388,11 @@ public class AppOpsService extends IAppOpsService.Stub { virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED); attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, - getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount); + getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags); if (shouldCollectAsyncNotedOp) { collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message, - shouldCollectMessage, notedCount); + shouldCollectMessage); } return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag, @@ -3563,7 +3551,7 @@ public class AppOpsService extends IAppOpsService.Stub { */ private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { Objects.requireNonNull(message); int callingUid = Binder.getCallingUid(); @@ -3571,51 +3559,42 @@ public class AppOpsService extends IAppOpsService.Stub { final long token = Binder.clearCallingIdentity(); try { synchronized (this) { + Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); + + RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); + AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, + attributionTag, message, System.currentTimeMillis()); + final boolean[] wasNoteForwarded = {false}; + if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0 && shouldCollectMessage) { reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag, message); } - Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); - RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); - if (callbacks == null) { - return; - } - - final boolean[] wasNoteForwarded = {false}; - if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) { - notedCount = 1; - } - - for (int i = 0; i < notedCount; i++) { - AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, - attributionTag, message, System.currentTimeMillis()); - wasNoteForwarded[0] = false; + if (callbacks != null) { callbacks.broadcast((cb) -> { try { cb.opNoted(asyncNotedOp); wasNoteForwarded[0] = true; } catch (RemoteException e) { Slog.e(TAG, - "Could not forward noteOp of " + opCode + " to " - + packageName + "Could not forward noteOp of " + opCode + " to " + packageName + "/" + uid + "(" + attributionTag + ")", e); } }); + } - if (!wasNoteForwarded[0]) { - ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get( - key); - if (unforwardedOps == null) { - unforwardedOps = new ArrayList<>(1); - mUnforwardedAsyncNotedOps.put(key, unforwardedOps); - } + if (!wasNoteForwarded[0]) { + ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key); + if (unforwardedOps == null) { + unforwardedOps = new ArrayList<>(1); + mUnforwardedAsyncNotedOps.put(key, unforwardedOps); + } - unforwardedOps.add(asyncNotedOp); - if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { - unforwardedOps.remove(0); - } + unforwardedOps.add(asyncNotedOp); + if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { + unforwardedOps.remove(0); } } } @@ -4047,7 +4026,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (shouldCollectAsyncNotedOp && !isRestricted) { collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF, - message, shouldCollectMessage, 1); + message, shouldCollectMessage); } return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag, @@ -7595,36 +7574,34 @@ public class AppOpsService extends IAppOpsService.Stub { public SyncNotedAppOp noteOperation(int code, int uid, String packageName, String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - String message, boolean shouldCollectMessage, int notedCount) { + String message, boolean shouldCollectMessage) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, notedCount, this::noteDelegateOperationImpl + shouldCollectMessage, this::noteDelegateOperationImpl ); } else { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl + shouldCollectMessage, AppOpsService.this::noteOperationImpl ); } } else if (mCheckOpsDelegate != null) { return noteDelegateOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } return noteOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId, virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount, AppOpsService.this::noteOperationImpl + AppOpsService.this::noteOperationImpl ); } diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index 4d114b4ad4ac..314664b0a79d 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -100,12 +100,10 @@ final class AttributedOp { * @param proxyDeviceId The device Id of the proxy * @param uidState UID state of the app noteOp/startOp was called for * @param flags OpFlags of the call - * @param accessCount The number of times the op is accessed */ public void accessed(int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId, - @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags, - int accessCount) { + @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) { long accessTime = System.currentTimeMillis(); accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId, uidState, flags); @@ -113,7 +111,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE, - DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount); + DiscreteRegistry.ACCESS_TYPE_NOTE_OP); } /** @@ -257,7 +255,7 @@ final class AttributedOp { if (isStarted) { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, startTime, - attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1); + attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP); } } @@ -453,7 +451,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, event.getUidState(), event.getFlags(), startTime, event.getAttributionFlags(), - event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1); + event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP); if (shouldSendActive) { mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, tag, event.getVirtualDeviceId(), true, diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 5e67f26ba1f6..6b0253864e2b 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -475,7 +475,7 @@ final class HistoricalRegistry { @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags, long accessTime, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId, - @DiscreteRegistry.AccessType int accessType, int accessCount) { + @DiscreteRegistry.AccessType int accessType) { synchronized (mInMemoryLock) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (!isPersistenceInitializedMLocked()) { @@ -484,7 +484,7 @@ final class HistoricalRegistry { } getUpdatedPendingHistoricalOpsMLocked( System.currentTimeMillis()).increaseAccessCount(op, uid, packageName, - attributionTag, uidState, flags, accessCount); + attributionTag, uidState, flags, 1); mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags, uidState, accessTime, -1, attributionFlags, diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java index 6d54be84d5e5..d78e98bf8e61 100644 --- a/services/core/java/com/android/server/pm/BroadcastHelper.java +++ b/services/core/java/com/android/server/pm/BroadcastHelper.java @@ -78,6 +78,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.BiFunction; +import java.util.function.Supplier; /** * Helper class to send broadcasts for various situations. @@ -216,7 +217,7 @@ public final class BroadcastHelper { filterExtrasForReceiver, bOptions); } - void sendResourcesChangedBroadcast(@NonNull Computer snapshot, + void sendResourcesChangedBroadcast(@NonNull Supplier<Computer> snapshotSupplier, boolean mediaStatus, boolean replacing, @NonNull String[] pkgNames, @@ -236,7 +237,7 @@ public final class BroadcastHelper { null /* targetPkg */, null /* finishedReceiver */, null /* userIds */, null /* instantUserIds */, null /* broadcastAllowList */, (callingUid, intentExtras) -> filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras), + snapshotSupplier, callingUid, intentExtras), null /* bOptions */, null /* requiredPermissions */); } @@ -544,7 +545,7 @@ public final class BroadcastHelper { }); } - void sendPostInstallBroadcasts(@NonNull Computer snapshot, + void sendPostInstallBroadcasts(@NonNull Supplier<Computer> snapshotSupplier, @NonNull InstallRequest request, @NonNull String packageName, @NonNull String requiredPermissionControllerPackage, @@ -567,8 +568,8 @@ public final class BroadcastHelper { final int[] uids = new int[]{request.getRemovedInfo().mUid}; notifyResourcesChanged( false /* mediaStatus */, true /* replacing */, pkgNames, uids); - sendResourcesChangedBroadcast( - snapshot, false /* mediaStatus */, true /* replacing */, pkgNames, uids); + sendResourcesChangedBroadcast(snapshotSupplier, + false /* mediaStatus */, true /* replacing */, pkgNames, uids); } sendPackageRemovedBroadcasts( request.getRemovedInfo(), packageSender, isKillApp, false /*removedBySystem*/, @@ -608,6 +609,7 @@ public final class BroadcastHelper { null /* broadcastAllowList */, null); } + final Computer snapshot = snapshotSupplier.get(); // Send installed broadcasts if the package is not a static shared lib. if (staticSharedLibraryName == null) { // Send PACKAGE_ADDED broadcast for users that see the package for the first time @@ -732,7 +734,7 @@ public final class BroadcastHelper { if (!isArchived) { final String[] pkgNames = new String[]{packageName}; final int[] uids = new int[]{request.getPkg().getUid()}; - sendResourcesChangedBroadcast(snapshot, + sendResourcesChangedBroadcast(snapshotSupplier, true /* mediaStatus */, true /* replacing */, pkgNames, uids); notifyResourcesChanged(true /* mediaStatus */, true /* replacing */, pkgNames, uids); @@ -860,8 +862,8 @@ public final class BroadcastHelper { * access all the packages in the extras. */ @Nullable - private static Bundle filterExtrasChangedPackageList(@NonNull Computer snapshot, int callingUid, - @NonNull Bundle extras) { + private static Bundle filterExtrasChangedPackageList( + @NonNull Supplier<Computer> snapshotSupplier, int callingUid, @NonNull Bundle extras) { if (UserHandle.isCore(callingUid)) { // see all return extras; @@ -873,6 +875,7 @@ public final class BroadcastHelper { final int userId = extras.getInt( Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(callingUid)); final int[] uids = extras.getIntArray(Intent.EXTRA_CHANGED_UID_LIST); + final Computer snapshot = snapshotSupplier.get(); final Pair<String[], int[]> filteredPkgs = filterPackages(snapshot, pkgs, uids, callingUid, userId); if (ArrayUtils.isEmpty(filteredPkgs.first)) { @@ -952,10 +955,12 @@ public final class BroadcastHelper { final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; final SparseArray<int[]> broadcastAllowList = isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds); + final String[] sharedUserPackages = + snapshot.getSharedUserPackagesForPackage(packageName, userId); mHandler.post(() -> sendPackageChangedBroadcastInternal( packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, setting.getPkg(), - snapshot.getSharedUserPackagesForPackage(packageName, userId))); + sharedUserPackages)); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } @@ -1120,7 +1125,7 @@ public final class BroadcastHelper { * @param uidList The uids of packages which have suspension changes. * @param userId The user where packages reside. */ - void sendPackagesSuspendedOrUnsuspendedForUser(@NonNull Computer snapshot, + void sendPackagesSuspendedOrUnsuspendedForUser(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String intent, @NonNull String[] pkgList, @NonNull int[] uidList, @@ -1138,7 +1143,7 @@ public final class BroadcastHelper { .toBundle(); BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver = (callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras); + snapshotSupplier, callingUid, intentExtras); mHandler.post(() -> sendPackageBroadcast(intent, null /* pkg */, extras, flags, null /* targetPkg */, null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */, @@ -1148,7 +1153,7 @@ public final class BroadcastHelper { null /* instantUserIds */, null /* broadcastAllowList */, filterExtrasForReceiver); } - void sendMyPackageSuspendedOrUnsuspended(@NonNull Computer snapshot, + void sendMyPackageSuspendedOrUnsuspended(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String[] affectedPackages, boolean suspended, int userId) { @@ -1163,6 +1168,7 @@ public final class BroadcastHelper { return; } final int[] targetUserIds = new int[] {userId}; + final Computer snapshot = snapshotSupplier.get(); for (String packageName : affectedPackages) { final Bundle appExtras = suspended ? SuspendPackageHelper.getSuspendedPackageAppExtras( @@ -1192,7 +1198,7 @@ public final class BroadcastHelper { * @param uidList The uids of packages which have suspension changes. * @param userId The user where packages reside. */ - void sendDistractingPackagesChanged(@NonNull Computer snapshot, + void sendDistractingPackagesChanged(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String[] pkgList, @NonNull int[] uidList, int userId, @@ -1208,11 +1214,11 @@ public final class BroadcastHelper { null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */, (callingUid, intentExtras) -> filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras), + snapshotSupplier, callingUid, intentExtras), null /* bOptions */, null /* requiredPermissions */)); } - void sendResourcesChangedBroadcastAndNotify(@NonNull Computer snapshot, + void sendResourcesChangedBroadcastAndNotify(@NonNull Supplier<Computer> snapshotSupplier, boolean mediaStatus, boolean replacing, @NonNull ArrayList<AndroidPackage> packages) { @@ -1224,7 +1230,7 @@ public final class BroadcastHelper { packageNames[i] = pkg.getPackageName(); packageUids[i] = pkg.getUid(); } - sendResourcesChangedBroadcast(snapshot, mediaStatus, + sendResourcesChangedBroadcast(snapshotSupplier, mediaStatus, replacing, packageNames, packageUids); notifyResourcesChanged(mediaStatus, replacing, packageNames, packageUids); } diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java index c5ec73b4e2b8..c4e981d487bc 100644 --- a/services/core/java/com/android/server/pm/DistractingPackageHelper.java +++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java @@ -123,7 +123,7 @@ public final class DistractingPackageHelper { if (!changedPackagesList.isEmpty()) { final String[] changedPackages = changedPackagesList.toArray( new String[changedPackagesList.size()]); - mBroadcastHelper.sendDistractingPackagesChanged(mPm.snapshotComputer(), + mBroadcastHelper.sendDistractingPackagesChanged(mPm::snapshotComputer, changedPackages, changedUids.toArray(), userId, restrictionFlags); mPm.scheduleWritePackageRestrictions(userId); } @@ -198,7 +198,7 @@ public final class DistractingPackageHelper { if (!changedPackages.isEmpty()) { final String[] packageArray = changedPackages.toArray( new String[changedPackages.size()]); - mBroadcastHelper.sendDistractingPackagesChanged(mPm.snapshotComputer(), + mBroadcastHelper.sendDistractingPackagesChanged(mPm::snapshotComputer, packageArray, changedUids.toArray(), userId, RESTRICTION_NONE); mPm.scheduleWritePackageRestrictions(userId); } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 69c6ce8ea0cd..183ceaecb70e 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -3084,7 +3084,7 @@ final class InstallPackageHelper { mPm.mProcessLoggingHandler.invalidateBaseApkHash(request.getPkg().getBaseApkPath()); } - mBroadcastHelper.sendPostInstallBroadcasts(mPm.snapshotComputer(), request, packageName, + mBroadcastHelper.sendPostInstallBroadcasts(mPm::snapshotComputer, request, packageName, mPm.mRequiredPermissionControllerPackage, mPm.mRequiredVerifierPackages, mPm.mRequiredInstallerPackage, /* packageSender= */ mPm, launchedForRestore, killApp, update, archived); diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index 951986fbd71a..a09d4776d986 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -227,7 +227,7 @@ public final class StorageEventHelper extends StorageEventListener { } if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); - mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), + mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm::snapshotComputer, true /* mediaStatus */, false /* replacing */, loaded); synchronized (mLoadedVolumes) { mLoadedVolumes.add(vol.getId()); @@ -279,7 +279,7 @@ public final class StorageEventHelper extends StorageEventListener { } if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); - mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), + mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm::snapshotComputer, false /* mediaStatus */, false /* replacing */, unloaded); synchronized (mLoadedVolumes) { mLoadedVolumes.remove(vol.getId()); diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index 4e70cc52ef90..88fd1aa159d3 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -192,21 +192,20 @@ public final class SuspendPackageHelper { } }); - final Computer newSnapshot = mPm.snapshotComputer(); if (!notifyPackagesList.isEmpty()) { final String[] changedPackages = notifyPackagesList.toArray(new String[0]); - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, suspended ? Intent.ACTION_PACKAGES_SUSPENDED : Intent.ACTION_PACKAGES_UNSUSPENDED, changedPackages, notifyUids.toArray(), quarantined, targetUserId); - mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages, - suspended, targetUserId); + mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(mPm::snapshotComputer, + changedPackages, suspended, targetUserId); mPm.scheduleWritePackageRestrictions(targetUserId); } // Send the suspension changed broadcast to ensure suspension state is not stale. if (!changedPackagesList.isEmpty()) { - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined, targetUserId); @@ -343,13 +342,12 @@ public final class SuspendPackageHelper { }); mPm.scheduleWritePackageRestrictions(targetUserId); - final Computer newSnapshot = mPm.snapshotComputer(); if (!unsuspendedPackages.isEmpty()) { final String[] packageArray = unsuspendedPackages.toArray( new String[unsuspendedPackages.size()]); - mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray, - false, targetUserId); - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(mPm::snapshotComputer, + packageArray, false, targetUserId); + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, Intent.ACTION_PACKAGES_UNSUSPENDED, packageArray, unsuspendedUids.toArray(), false, targetUserId); } diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java index 041f2d3a459d..04ce4e692fef 100644 --- a/services/core/java/com/android/server/pm/UserDataPreparer.java +++ b/services/core/java/com/android/server/pm/UserDataPreparer.java @@ -68,6 +68,10 @@ class UserDataPreparer { void prepareUserData(UserInfo userInfo, int flags) { try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { final StorageManager storage = mContext.getSystemService(StorageManager.class); + if (storage == null) { + Log.e(TAG, "prepareUserData failed due to unable get StorageManager"); + return; + } /* * Internal storage must be prepared before adoptable storage, since the user's volume * keys are stored in their internal storage. @@ -159,14 +163,16 @@ class UserDataPreparer { void destroyUserData(int userId, int flags) { try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { final StorageManager storage = mContext.getSystemService(StorageManager.class); - /* - * Volume destruction order isn't really important, but to avoid any weird issues we - * process internal storage last, the opposite of prepareUserData. - */ - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - if (volumeUuid != null) { - destroyUserDataLI(volumeUuid, userId, flags); + if (storage != null) { + /* + * Volume destruction order isn't really important, but to avoid any weird issues we + * process internal storage last, the opposite of prepareUserData. + */ + for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { + final String volumeUuid = vol.getFsUuid(); + if (volumeUuid != null) { + destroyUserDataLI(volumeUuid, userId, flags); + } } } destroyUserDataLI(null /* internal storage */, userId, flags); @@ -194,9 +200,10 @@ class UserDataPreparer { } } - // All the user's data directories should be empty now, so finish the job. - storage.destroyUserStorage(volumeUuid, userId, flags); - + if (storage != null) { + // All the user's data directories should be empty now, so finish the job. + storage.destroyUserStorage(volumeUuid, userId, flags); + } } catch (Exception e) { logCriticalInfo(Log.WARN, "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e); diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java index e989d6875d15..e9cb279439a6 100644 --- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java +++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java @@ -40,7 +40,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; @@ -351,22 +351,22 @@ public interface AccessCheckDelegate extends CheckPermissionDelegate, CheckOpsDe @Override public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, Integer, SyncNotedAppOp> superImpl) { + @Nullable String message, boolean shouldCollectMessage, + @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, SyncNotedAppOp> superImpl) { if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } finally { Binder.restoreCallingIdentity(identity); } } return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @Override diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 33210e28281e..ecffd382f542 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -53,7 +53,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; @@ -246,12 +246,11 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, - Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) { + boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String, + Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), resolveUid(code, uid), packageName, attributionTag, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @Override diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 8c588b4c9b98..63e8d9973237 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -195,22 +195,23 @@ public class BatteryUsageStatsProvider { mLastAccumulationMonotonicHistorySize = historySize; } - // No need to store the accumulated stats asynchronously, as the entire accumulation - // operation is async - handler.post(() -> accumulateBatteryUsageStats(stats, false)); + handler.post(() -> accumulateBatteryUsageStats(stats)); } /** * Computes BatteryUsageStats for the period since the last accumulated stats were stored, - * adds them to the accumulated stats and asynchronously saves the result. + * adds them to the accumulated stats and saves the result. */ public void accumulateBatteryUsageStats(BatteryStatsImpl stats) { - accumulateBatteryUsageStats(stats, true); - } - - private void accumulateBatteryUsageStats(BatteryStatsImpl stats, boolean storeAsync) { AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats(); - updateAccumulatedBatteryUsageStats(accumulatedStats, stats); + + final BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder() + .setMaxStatsAgeMs(0) + .includeProcessStateData() + .includePowerStateData() + .includeScreenStateData() + .build(); + updateAccumulatedBatteryUsageStats(accumulatedStats, stats, query); PowerStatsSpan powerStatsSpan = new PowerStatsSpan(AccumulatedBatteryUsageStatsSection.ID); powerStatsSpan.addSection( @@ -219,13 +220,8 @@ public class BatteryUsageStatsProvider { accumulatedStats.startWallClockTime, accumulatedStats.endMonotonicTime - accumulatedStats.startMonotonicTime); mMonotonicClock.write(); - if (storeAsync) { - mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan, - accumulatedStats.builder::discard); - } else { - mPowerStatsStore.storePowerStatsSpan(powerStatsSpan); - accumulatedStats.builder.discard(); - } + mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan, + accumulatedStats.builder::discard); } /** @@ -273,7 +269,7 @@ public class BatteryUsageStatsProvider { BatteryUsageStats batteryUsageStats; if ((query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_ACCUMULATED) != 0) { - batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query); + batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query, currentTimeMs); } else if (query.getAggregatedToTimestamp() == 0) { BatteryUsageStats.Builder builder = computeBatteryUsageStats(stats, query, query.getMonotonicStartTime(), @@ -292,13 +288,9 @@ public class BatteryUsageStatsProvider { } private BatteryUsageStats getAccumulatedBatteryUsageStats(BatteryStatsImpl stats, - BatteryUsageStatsQuery query) { + BatteryUsageStatsQuery query, long currentTimeMs) { AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats(); - if (accumulatedStats.endMonotonicTime == MonotonicClock.UNDEFINED - || mMonotonicClock.monotonicTime() - accumulatedStats.endMonotonicTime - > query.getMaxStatsAge()) { - updateAccumulatedBatteryUsageStats(accumulatedStats, stats); - } + updateAccumulatedBatteryUsageStats(accumulatedStats, stats, query); return accumulatedStats.builder.build(); } @@ -329,7 +321,7 @@ public class BatteryUsageStatsProvider { } private void updateAccumulatedBatteryUsageStats(AccumulatedBatteryUsageStats accumulatedStats, - BatteryStatsImpl stats) { + BatteryStatsImpl stats, BatteryUsageStatsQuery query) { long startMonotonicTime = accumulatedStats.endMonotonicTime; if (startMonotonicTime == MonotonicClock.UNDEFINED) { startMonotonicTime = stats.getMonotonicStartTime(); @@ -341,7 +333,6 @@ public class BatteryUsageStatsProvider { accumulatedStats.builder = new BatteryUsageStats.Builder( stats.getCustomEnergyConsumerNames(), true, true, true, 0); accumulatedStats.startWallClockTime = stats.getStartClockTime(); - accumulatedStats.startMonotonicTime = stats.getMonotonicStartTime(); accumulatedStats.builder.setStatsStartTimestamp(accumulatedStats.startWallClockTime); } @@ -351,7 +342,7 @@ public class BatteryUsageStatsProvider { accumulatedStats.builder.setStatsDuration(endWallClockTime - startMonotonicTime); mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, stats.getHistory(), - startMonotonicTime, endMonotonicTime); + startMonotonicTime, MonotonicClock.UNDEFINED); populateGeneralInfo(accumulatedStats.builder, stats); } diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java index 2609cf7aebfc..dcdd3bd8b3fa 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java @@ -23,7 +23,6 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.BatteryStatsHistoryIterator; -import com.android.internal.os.MonotonicClock; import java.util.function.Consumer; @@ -170,9 +169,6 @@ public class PowerStatsAggregator { } } } - if (endTimeMs != MonotonicClock.UNDEFINED) { - lastTime = endTimeMs; - } if (lastTime > baseTime) { mStats.setDuration(lastTime - baseTime); mStats.finish(lastTime); diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java index 24ed1bbe0eb1..57a0bb53c9dc 100644 --- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java +++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -343,6 +345,11 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } + if (mPersister.mSnapshotPersistQueue.peekWriteQueueSize() >= MAX_STORE_QUEUE_DEPTH + || mPersister.mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { + Slog.w(TAG, "Skipping recording activity snapshot, too many requests!"); + return; + } final int size = activity.size(); final int[] mixedCode = new int[size]; if (size == 1) { @@ -432,7 +439,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord addBelowActivityIfExist(ar, mPendingLoadActivity, false, "load-snapshot"); } else { // remove the snapshot for the one below close - addBelowActivityIfExist(ar, mPendingRemoveActivity, true, "remove-snapshot"); + addBelowActivityIfExist(ar, mPendingRemoveActivity, false, "remove-snapshot"); } } diff --git a/services/core/java/com/android/server/wm/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/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt index de029e0d770f..90e1263b76ec 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt @@ -56,8 +56,8 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendDistractingPackagesChanged(any(Computer::class.java), - pkgListCaptor.capture(), any(), any(), flagsCaptor.capture()) + verify(broadcastHelper).sendDistractingPackagesChanged( + any(), pkgListCaptor.capture(), any(), any(), flagsCaptor.capture()) val modifiedPackages = pkgListCaptor.value val distractionFlags = flagsCaptor.value @@ -158,8 +158,7 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) verify(broadcastHelper).sendDistractingPackagesChanged( - any(Computer::class.java), pkgListCaptor.capture(), any(), eq(TEST_USER_ID), - flagsCaptor.capture()) + any(), pkgListCaptor.capture(), any(), eq(TEST_USER_ID), flagsCaptor.capture()) val modifiedPackages = pkgListCaptor.value val distractionFlags = flagsCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -198,12 +197,12 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { @Test fun sendDistractingPackagesChanged() { - broadcastHelper.sendDistractingPackagesChanged(pms.snapshotComputer(), + broadcastHelper.sendDistractingPackagesChanged(pms::snapshotComputer, packagesToChange, uidsToChange, TEST_USER_ID, PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) testHandler.flush() - verify(broadcastHelper).sendDistractingPackagesChanged(any(Computer::class.java), - pkgListCaptor.capture(), uidsCaptor.capture(), eq(TEST_USER_ID), any()) + verify(broadcastHelper).sendDistractingPackagesChanged( + any(), pkgListCaptor.capture(), uidsCaptor.capture(), eq(TEST_USER_ID), any()) var changedPackages = pkgListCaptor.value var changedUids = uidsCaptor.value diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt index 7444403f88c8..60e82501db1c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt @@ -58,8 +58,8 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_SUSPENDED), pkgListCaptor.capture(), any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(), + eq(Intent.ACTION_PACKAGES_SUSPENDED), pkgListCaptor.capture(), any(), any(), any()) var modifiedPackages = pkgListCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -149,11 +149,11 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_UNSUSPENDED), pkgListCaptor.capture(), any(), any(), - any()) - verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended(any(Computer::class.java), - any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser( + any(), eq(Intent.ACTION_PACKAGES_UNSUSPENDED), + pkgListCaptor.capture(), any(), any(), any()) + verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended( + any(), any(), any(), any()) var modifiedPackages = pkgListCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -230,10 +230,10 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_UNSUSPENDED), any(), any(), any(), any()) - verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended(any(Computer::class.java), - any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser( + any(), eq(Intent.ACTION_PACKAGES_UNSUSPENDED), any(), any(), any(), any()) + verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended( + any(), any(), any(), any()) assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(), TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull() diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java index 73dcfe77e67f..709f83ba907d 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java @@ -36,7 +36,6 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.ConditionVariable; -import android.os.Handler; import android.os.Parcel; import android.os.Process; import android.os.UidBatteryConsumer; @@ -82,9 +81,8 @@ public class BatteryUsageStatsProviderTest { .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0); private MockClock mMockClock = mStatsRule.getMockClock(); - private MonotonicClock mMonotonicClock = mStatsRule.getMonotonicClock(); + private MonotonicClock mMonotonicClock = new MonotonicClock(666777, mMockClock); private Context mContext; - private PowerStatsStore mPowerStatsStore; @Before public void setup() throws IOException { @@ -95,9 +93,6 @@ public class BatteryUsageStatsProviderTest { } else { mContext = InstrumentationRegistry.getContext(); } - mPowerStatsStore = spy(new PowerStatsStore( - new File(mStatsRule.getHistoryDir(), getClass().getSimpleName()), - mStatsRule.getHandler())); } @Test @@ -279,7 +274,10 @@ public class BatteryUsageStatsProviderTest { powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, true); - BatteryUsageStatsProvider provider = createBatteryUsageStatsProvider(0); + BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext, + powerAttributor, mStatsRule.getPowerProfile(), + mStatsRule.getCpuScalingPolicies(), mock(PowerStatsStore.class), 0, mMockClock, + mMonotonicClock); return provider.getBatteryUsageStats(batteryStats, BatteryUsageStatsQuery.DEFAULT); } @@ -333,30 +331,30 @@ public class BatteryUsageStatsProviderTest { BatteryStats.HistoryItem item; assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 2_000_000); assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isEqualTo(0); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START, "foo", APP_UID, 3_600_000, 90, 3_000_000); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH, "foo", APP_UID, 3_600_000, 90, 3_001_000); @@ -443,15 +441,14 @@ public class BatteryUsageStatsProviderTest { assertThat(item.eventTag.string).startsWith(uid + " "); assertThat(item.batteryChargeUah).isEqualTo(3_600_000); assertThat(item.batteryLevel).isEqualTo(90); - assertThat(item.time).isEqualTo(batteryStats.getMonotonicStartTime() + 1_000_000); + assertThat(item.time).isEqualTo((long) 1_000_000); } assertThat(expectedUid).isEqualTo(200); } - private void assertHistoryItem(MockBatteryStatsImpl batteryStats, BatteryStats.HistoryItem item, - int command, int eventCode, String tag, int uid, int batteryChargeUah, int batteryLevel, - long elapsedTimeMs) { + private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode, + String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) { assertThat(item.cmd).isEqualTo(command); assertThat(item.eventCode).isEqualTo(eventCode); if (tag == null) { @@ -463,7 +460,7 @@ public class BatteryUsageStatsProviderTest { assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah); assertThat(item.batteryLevel).isEqualTo(batteryLevel); - assertThat(item.time).isEqualTo(batteryStats.getMonotonicStartTime() + elapsedTimeMs); + assertThat(item.time).isEqualTo(elapsedTimeMs); } @Test @@ -569,66 +566,38 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); assertThat(stats.getStatsEndTimestamp()).isEqualTo(55 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 180.0, (10 + 20) * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 180.0, (10 + 20) * MINUTE_IN_MS); + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isWithin(0.0001) + .of(180.0); // 360 mA * 0.5 hours + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isEqualTo((10 + 20) * MINUTE_IN_MS); + final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream() + .filter(uid -> uid.getUid() == APP_UID).findFirst().get(); + assertThat(uidBatteryConsumer + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isWithin(0.1) + .of(180.0); stats.close(); } @Test public void accumulateBatteryUsageStats() throws Throwable { - MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - accumulateBatteryUsageStats(batteryStats, 10000000, 0); + accumulateBatteryUsageStats(10000000, 1); // Accumulate every 200 bytes of battery history - accumulateBatteryUsageStats(batteryStats, 200, 2); - accumulateBatteryUsageStats(batteryStats, 50, 4); + accumulateBatteryUsageStats(200, 2); + accumulateBatteryUsageStats(50, 5); // Accumulate on every invocation of accumulateBatteryUsageStats - accumulateBatteryUsageStats(batteryStats, 0, 7); + accumulateBatteryUsageStats(0, 7); } - @Test - public void getAccumulatedBatteryUsageStats() throws Throwable { - MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - - // Only accumulate the first 25 minutes - accumulateBatteryUsageStats(batteryStats, 200, 1); - - BatteryUsageStatsProvider batteryUsageStatsProvider = createBatteryUsageStatsProvider(200); - - // At this point the last stored accumulated stats are `115 - 30 = 85` minutes old - BatteryUsageStats stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, - new BatteryUsageStatsQuery.Builder() - .accumulated() - .setMaxStatsAgeMs(90 * MINUTE_IN_MS) - .build()); - - assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); - assertThat(stats.getStatsEndTimestamp()).isEqualTo(30 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 60.0, 10 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 60.0, 10 * MINUTE_IN_MS); - - stats.close(); - - // Now force the usage stats to catch up to the current time - stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, - new BatteryUsageStatsQuery.Builder() - .accumulated() - .setMaxStatsAgeMs(5 * MINUTE_IN_MS) - .build()); - - assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); - assertThat(stats.getStatsEndTimestamp()).isEqualTo(115 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); - - stats.close(); - } - - private void accumulateBatteryUsageStats(MockBatteryStatsImpl batteryStatsImpl, - int accumulatedBatteryUsageStatsSpanSize, int expectedNumberOfUpdates) - throws Throwable { - Handler handler = mStatsRule.getHandler(); - MockBatteryStatsImpl batteryStats = spy(batteryStatsImpl); + private void accumulateBatteryUsageStats(int accumulatedBatteryUsageStatsSpanSize, + int expectedNumberOfUpdates) throws Throwable { + BatteryStatsImpl batteryStats = spy(mStatsRule.getBatteryStats()); // Note - these two are in microseconds when(batteryStats.computeBatteryTimeRemaining(anyLong())).thenReturn(111_000L); when(batteryStats.computeChargeTimeRemaining(anyLong())).thenReturn(777_000L); @@ -641,76 +610,82 @@ public class BatteryUsageStatsProviderTest { batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); } - mPowerStatsStore.reset(); + PowerStatsStore powerStatsStore = spy(new PowerStatsStore( + new File(mStatsRule.getHistoryDir(), getClass().getSimpleName()), + mStatsRule.getHandler())); + powerStatsStore.reset(); int[] count = new int[1]; doAnswer(inv -> { count[0]++; - return inv.callRealMethod(); - }).when(mPowerStatsStore).storePowerStatsSpan(any(PowerStatsSpan.class)); + return null; + }).when(powerStatsStore).storePowerStatsSpan(any(PowerStatsSpan.class)); - BatteryUsageStatsProvider batteryUsageStatsProvider = createBatteryUsageStatsProvider( - accumulatedBatteryUsageStatsSpanSize); + MultiStatePowerAttributor powerAttributor = new MultiStatePowerAttributor(mContext, + powerStatsStore, mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), + () -> 3500); + for (int powerComponentId = 0; powerComponentId < BatteryConsumer.POWER_COMPONENT_COUNT; + powerComponentId++) { + powerAttributor.setPowerComponentSupported(powerComponentId, true); + } + powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_ANY, true); + + BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext, + powerAttributor, mStatsRule.getPowerProfile(), + mStatsRule.getCpuScalingPolicies(), powerStatsStore, + accumulatedBatteryUsageStatsSpanSize, mMockClock, mMonotonicClock); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(10 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(20 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(30 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - // Make sure the accumulated stats are computed and saved before generating more history - mStatsRule.waitForBackgroundThread(); - - setTime(50 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); } setTime(55 * MINUTE_IN_MS); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); // This section has not been saved yet, but should be added to the accumulated totals - setTime(80 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(110 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); } setTime(115 * MINUTE_IN_MS); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + // Pick up the remainder of battery history that has not yet been accumulated + provider.accumulateBatteryUsageStats(batteryStats); mStatsRule.waitForBackgroundThread(); - BatteryUsageStats stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, + BatteryUsageStats stats = provider.getBatteryUsageStats(batteryStats, new BatteryUsageStatsQuery.Builder().accumulated().build()); assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); @@ -721,55 +696,29 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getBatteryCapacity()).isEqualTo(4000); // from PowerProfile // Total: 10 + 20 + 30 = 60 - assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); - stats.close(); - - mStatsRule.waitForBackgroundThread(); - - assertThat(count[0]).isEqualTo(expectedNumberOfUpdates); - } - - private BatteryUsageStatsProvider createBatteryUsageStatsProvider( - int accumulatedBatteryUsageStatsSpanSize) { - MultiStatePowerAttributor powerAttributor = new MultiStatePowerAttributor(mContext, - mPowerStatsStore, mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), - () -> 3500); - for (int powerComponentId = 0; powerComponentId < BatteryConsumer.POWER_COMPONENT_COUNT; - powerComponentId++) { - powerAttributor.setPowerComponentSupported(powerComponentId, true); - } - powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_ANY, true); - - return new BatteryUsageStatsProvider(mContext, powerAttributor, - mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), mPowerStatsStore, - accumulatedBatteryUsageStatsSpanSize, mMockClock, mMonotonicClock); - } - - private static void assertBatteryConsumer(BatteryUsageStats stats, double expectedPowerMah, - long expectedDurationMs) { - AggregateBatteryConsumer aggregatedConsumer = stats.getAggregateBatteryConsumer( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); - assertThat(aggregatedConsumer + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isWithin(0.0001) - .of(expectedPowerMah); - assertThat(aggregatedConsumer + .of(360.0); // 360 mA * 1.0 hour + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) - .isEqualTo(expectedDurationMs); - } + .isEqualTo(60 * MINUTE_IN_MS); - private static void assertBatteryConsumer(BatteryUsageStats stats, int uid, - double expectedPowerMah, long expectedDurationMs) { final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream() - .filter(u -> u.getUid() == uid).findFirst().get(); + .filter(uid -> uid.getUid() == APP_UID).findFirst().get(); assertThat(uidBatteryConsumer .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isWithin(0.1) - .of(expectedPowerMah); + .of(360.0); assertThat(uidBatteryConsumer .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) - .isEqualTo(expectedDurationMs); + .isEqualTo(60 * MINUTE_IN_MS); + + assertThat(count[0]).isEqualTo(expectedNumberOfUpdates); + + stats.close(); } private void setTime(long timeMs) { diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java index 9e7e0b646047..a3c7ece386c7 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java @@ -41,7 +41,6 @@ import android.util.SparseArray; import android.util.Xml; import com.android.internal.os.CpuScalingPolicies; -import com.android.internal.os.MonotonicClock; import com.android.internal.os.PowerProfile; import com.android.internal.power.EnergyConsumerStats; @@ -66,7 +65,6 @@ public class BatteryUsageStatsRule implements TestRule { private final PowerProfile mPowerProfile; private final MockClock mMockClock = new MockClock(); - private final MonotonicClock mMonotonicClock = new MonotonicClock(666777, mMockClock); private String mTestName; private boolean mCreateTempDirectory; private File mHistoryDir; @@ -120,7 +118,7 @@ public class BatteryUsageStatsRule implements TestRule { clearDirectory(); } mBatteryStats = new MockBatteryStatsImpl(mBatteryStatsConfigBuilder.build(), - mMockClock, mMonotonicClock, mHistoryDir, mHandler, new PowerStatsUidResolver()); + mMockClock, mHistoryDir, mHandler, new PowerStatsUidResolver()); mBatteryStats.setPowerProfile(mPowerProfile); mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy)); synchronized (mBatteryStats) { @@ -146,10 +144,6 @@ public class BatteryUsageStatsRule implements TestRule { return mMockClock; } - public MonotonicClock getMonotonicClock() { - return mMonotonicClock; - } - public Handler getHandler() { return mHandler; } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java index 9a38209a7d17..b374a3202fa2 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java @@ -77,15 +77,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { new PowerStatsUidResolver()); } - MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, - File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) { - this(config, clock, new MonotonicClock(0, clock), historyDirectory, handler, - powerStatsUidResolver); - } - - MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, MonotonicClock monotonicClock, - File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) { - super(config, clock, monotonicClock, historyDirectory, handler, + MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory, + Handler handler, PowerStatsUidResolver powerStatsUidResolver) { + super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler, mock(PlatformIdleStateCallback.class), mock(EnergyStatsRetriever.class), mock(UserInfoProvider.class), mockPowerProfile(), new CpuScalingPolicies(new SparseArray<>(), new SparseArray<>()), diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java index d243f92a139f..38fe6134d992 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java @@ -408,7 +408,7 @@ public class PowerStatsExporterTest { BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( new String[]{"cu570m"}, /* includeProcessStateData */ true, true, true, /* powerThreshold */ 0); - exportAggregatedPowerStats(builder, 3700, 7500); + exportAggregatedPowerStats(builder, 3700, 6700); BatteryUsageStats actual = builder.build(); String message = "Actual BatteryUsageStats: " + actual; diff --git a/services/tests/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/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..4e5a246ef773 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -18,11 +18,13 @@ package android.telephony; import static android.text.TextUtils.formatSimple; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.telephony.cdma.CdmaCellLocation; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -30,7 +32,11 @@ import java.util.Objects; /** * CellIdentity is to represent a unique CDMA cell + * + * @deprecated Legacy CDMA is unsupported. */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated public final class CellIdentityCdma extends CellIdentity { private static final String TAG = CellIdentityCdma.class.getSimpleName(); private static final boolean DBG = false; @@ -124,7 +130,11 @@ public final class CellIdentityCdma extends CellIdentity { return new CellIdentityCdma(this); } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellIdentityCdma sanitizeLocationInfo() { return new CellIdentityCdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, @@ -157,7 +167,11 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return Network Id 0..65535, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getNetworkId() { return mNetworkId; } @@ -165,7 +179,11 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return System Id 0..32767, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getSystemId() { return mSystemId; } @@ -173,7 +191,10 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return Base Station Id 0..65535, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getBasestationId() { return mBasestationId; } @@ -184,7 +205,11 @@ public final class CellIdentityCdma extends CellIdentity { * of 0.25 seconds and ranges from -2592000 to 2592000, both * values inclusive (corresponding to a range of -180 * to +180 degrees). {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getLongitude() { return mLongitude; } @@ -195,7 +220,11 @@ public final class CellIdentityCdma extends CellIdentity { * of 0.25 seconds and ranges from -1296000 to 1296000, both * values inclusive (corresponding to a range of -90 * to +90 degrees). {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getLatitude() { return mLatitude; } @@ -206,7 +235,11 @@ public final class CellIdentityCdma extends CellIdentity { super.hashCode()); } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @NonNull @Override public CdmaCellLocation asCellLocation() { @@ -277,7 +310,13 @@ public final class CellIdentityCdma extends CellIdentity { if (DBG) log(toString()); } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressWarnings("hiding") public static final @android.annotation.NonNull Creator<CellIdentityCdma> CREATOR = new Creator<CellIdentityCdma>() { diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java index aa8cff52bcaf..3c4bb5164ffc 100644 --- a/telephony/java/android/telephony/CellInfoCdma.java +++ b/telephony/java/android/telephony/CellInfoCdma.java @@ -16,17 +16,23 @@ package android.telephony; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; import com.android.telephony.Rlog; /** * A {@link CellInfo} representing a CDMA cell that provides identity and measurement info. + * + * @deprecated Legacy CDMA is unsupported. */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated public final class CellInfoCdma extends CellInfo implements Parcelable { private static final String LOG_TAG = "CellInfoCdma"; @@ -61,7 +67,10 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { /** * @return a {@link CellIdentityCdma} instance. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellIdentityCdma getCellIdentity() { return mCellIdentityCdma; @@ -75,7 +84,10 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { /** * @return a {@link CellSignalStrengthCdma} instance. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellSignalStrengthCdma getCellSignalStrength() { return mCellSignalStrengthCdma; @@ -135,7 +147,12 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { return 0; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags, TYPE_CDMA); @@ -154,7 +171,12 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { if (DBG) log("CellInfoCdma(Parcel): " + toString()); } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final @android.annotation.NonNull Creator<CellInfoCdma> CREATOR = new Creator<CellInfoCdma>() { @Override public CellInfoCdma createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index d9437ab29881..2d650ab20802 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -255,25 +255,75 @@ public final class PreciseDisconnectCause { @FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) public static final int EMERGENCY_PERM_FAILURE = 326; - /** Mobile station (MS) is locked until next power cycle. */ + /** + * Mobile station (MS) is locked until next power cycle. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; - /** Drop call. */ + /** + * Drop call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_DROP = 1001; - /** INTERCEPT order received, Mobile station (MS) state idle entered. */ + /** + * INTERCEPT order received, Mobile station (MS) state idle entered. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_INTERCEPT = 1002; - /** Mobile station (MS) has been redirected, call is cancelled. */ + /** + * Mobile station (MS) has been redirected, call is cancelled. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_REORDER = 1003; - /** Service option rejection. */ + /** + * Service option rejection. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_SO_REJECT = 1004; - /** Requested service is rejected, retry delay is set. */ + /** + * Requested service is rejected, retry delay is set. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_RETRY_ORDER = 1005; - /** Unable to obtain access to the CDMA system. */ + /** + * Unable to obtain access to the CDMA system. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ACCESS_FAILURE = 1006; - /** Not a preempted call. */ + /** + * Not a preempted call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_PREEMPTED = 1007; - /** Not an emergency call. */ + /** + * Not an emergency call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_NOT_EMERGENCY = 1008; - /** Access Blocked by CDMA network. */ + /** + * Access Blocked by CDMA network. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ACCESS_BLOCKED = 1009; /* OEM specific error codes. To be used by OEMs when they don't want to diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index aec11c45008a..453f8220c6c6 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1397,25 +1397,44 @@ public class TelephonyManager { /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which leaves the roaming * mode set to the radio default or to the user's preference if they've indicated one. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which only permits * connections on home networks. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_HOME = 0; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on * affiliated networks. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on * any network. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_ANY = 2; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef(prefix = { "CDMA_ROAMING_MODE_" }, value = { CDMA_ROAMING_MODE_RADIO_DEFAULT, CDMA_ROAMING_MODE_HOME, @@ -1802,12 +1821,17 @@ public class TelephonyManager { * to indicate if the SIM combination in DSDS has limitation or compatible issue. * e.g. two CDMA SIMs may disrupt each other's voice call in certain scenarios. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE = "android.telephony.extra.SIM_COMBINATION_WARNING_TYPE"; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef({ EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE, EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA @@ -1818,15 +1842,21 @@ public class TelephonyManager { /** * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE} * to indicate there's no SIM combination warning. + * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0; /** * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE} * to indicate two active SIMs are both CDMA hence there might be functional limitation. + * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1; /** @@ -1835,6 +1865,7 @@ public class TelephonyManager { * e.g. two CDMA SIMs may disrupt each other's voice call in certain scenarios, and the * name will be "operator1 & operator2". * + * TODO(b/379356026): Deprecate if this is CDMA specific * @hide */ public static final String EXTRA_SIM_COMBINATION_NAMES = @@ -2414,9 +2445,12 @@ public class TelephonyManager { * higher, then a SecurityException is thrown.</li> * </ul> * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -2456,9 +2490,12 @@ public class TelephonyManager { * * @param slotIndex of which MEID is returned * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -2485,9 +2522,12 @@ public class TelephonyManager { * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not * available. * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode() { @@ -2500,9 +2540,12 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode(int slotIndex) { @@ -2648,7 +2691,13 @@ public class TelephonyManager { public static final int PHONE_TYPE_NONE = PhoneConstants.PHONE_TYPE_NONE; /** Phone radio is GSM. */ public static final int PHONE_TYPE_GSM = PhoneConstants.PHONE_TYPE_GSM; - /** Phone radio is CDMA. */ + /** + * Phone radio is CDMA. + * + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA; /** Phone is via SIP. */ public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP; @@ -3070,13 +3119,33 @@ public class TelephonyManager { public static final int NETWORK_TYPE_EDGE = TelephonyProtoEnums.NETWORK_TYPE_EDGE; // = 2. /** Current network is UMTS */ public static final int NETWORK_TYPE_UMTS = TelephonyProtoEnums.NETWORK_TYPE_UMTS; // = 3. - /** Current network is CDMA: Either IS95A or IS95B*/ + /** + * Current network is CDMA: Either IS95A or IS95B + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_CDMA = TelephonyProtoEnums.NETWORK_TYPE_CDMA; // = 4. - /** Current network is EVDO revision 0*/ + /** + * Current network is EVDO revision 0 + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_0 = TelephonyProtoEnums.NETWORK_TYPE_EVDO_0; // = 5. - /** Current network is EVDO revision A*/ + /** + * Current network is EVDO revision A + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_A = TelephonyProtoEnums.NETWORK_TYPE_EVDO_A; // = 6. - /** Current network is 1xRTT*/ + /** + * Current network is 1xRTT + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_1xRTT = TelephonyProtoEnums.NETWORK_TYPE_1XRTT; // = 7. /** Current network is HSDPA */ public static final int NETWORK_TYPE_HSDPA = TelephonyProtoEnums.NETWORK_TYPE_HSDPA; // = 8. @@ -3090,11 +3159,21 @@ public class TelephonyManager { */ @Deprecated public static final int NETWORK_TYPE_IDEN = TelephonyProtoEnums.NETWORK_TYPE_IDEN; // = 11. - /** Current network is EVDO revision B*/ + /** + * Current network is EVDO revision B + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_B = TelephonyProtoEnums.NETWORK_TYPE_EVDO_B; // = 12. /** Current network is LTE */ public static final int NETWORK_TYPE_LTE = TelephonyProtoEnums.NETWORK_TYPE_LTE; // = 13. - /** Current network is eHRPD */ + /** + * Current network is eHRPD + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EHRPD = TelephonyProtoEnums.NETWORK_TYPE_EHRPD; // = 14. /** Current network is HSPA+ */ public static final int NETWORK_TYPE_HSPAP = TelephonyProtoEnums.NETWORK_TYPE_HSPAP; // = 15. @@ -6773,9 +6852,13 @@ public class TelephonyManager { } } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"ERI_"}, value = { + -1, ERI_ON, ERI_OFF, ERI_FLASH @@ -6785,24 +6868,37 @@ public class TelephonyManager { /** * ERI (Enhanced Roaming Indicator) is ON i.e value 0 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_ON = 0; /** * ERI (Enhanced Roaming Indicator) is OFF i.e value 1 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_OFF = 1; /** * ERI (Enhanced Roaming Indicator) is FLASH i.e value 2 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_FLASH = 2; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"ERI_ICON_MODE_"}, value = { + -1, ERI_ICON_MODE_NORMAL, ERI_ICON_MODE_FLASH }) @@ -6814,7 +6910,9 @@ public class TelephonyManager { * * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1 * @hide + * @deprecated Legacy CDMA is unsupported. */ + @Deprecated public static final int ERI_ICON_MODE_NORMAL = 0; /** @@ -6823,7 +6921,9 @@ public class TelephonyManager { * * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1 * @hide + * @deprecated Legacy CDMA is unsupported. */ + @Deprecated public static final int ERI_ICON_MODE_FLASH = 1; /** @@ -6831,10 +6931,13 @@ public class TelephonyManager { * 3GPP2 C.R1001-H v1.0 Table 8.1-1. Additionally carriers define their own ERI display numbers. * Defined values are {@link #ERI_ON}, {@link #ERI_OFF}, and {@link #ERI_FLASH}. * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -6844,8 +6947,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI icon index to display for a subscription. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @UnsupportedAppUsage public @EriIconIndex int getCdmaEriIconIndex(int subId) { @@ -6868,8 +6973,10 @@ public class TelephonyManager { * 0 - ON * 1 - FLASHING * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @UnsupportedAppUsage public @EriIconMode int getCdmaEriIconMode(int subId) { @@ -6890,8 +6997,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI text, * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getCdmaEriText() { return getCdmaEriText(getSubId()); @@ -6900,8 +7009,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI text, of a subscription * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @UnsupportedAppUsage public String getCdmaEriText(int subId) { @@ -8178,8 +8289,10 @@ public class TelephonyManager { * @param itemID the ID of the item to read. * @return the NV item as a String, or null on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @UnsupportedAppUsage public String nvReadItem(int itemID) { try { @@ -8206,8 +8319,10 @@ public class TelephonyManager { * @param itemValue the value to write, as a String. * @return true on success; false on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public boolean nvWriteItem(int itemID, String itemValue) { try { ITelephony telephony = getITelephony(); @@ -8232,8 +8347,10 @@ public class TelephonyManager { * @param preferredRoamingList byte array containing the new PRL. * @return true on success; false on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) { try { ITelephony telephony = getITelephony(); @@ -8260,11 +8377,13 @@ 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) { try { ITelephony telephony = getITelephony(); @@ -8295,10 +8414,13 @@ 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) @@ -8331,6 +8453,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) @@ -9284,20 +9407,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; /** @@ -9308,8 +9437,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; /** @@ -9320,8 +9451,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; @@ -9391,14 +9524,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; @@ -9416,8 +9553,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; @@ -9430,8 +9569,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; @@ -9470,8 +9611,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; @@ -10552,8 +10695,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10564,8 +10710,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10585,8 +10734,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10597,8 +10749,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11887,8 +12042,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11931,8 +12089,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11954,7 +12115,10 @@ public class TelephonyManager { } } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef(prefix = { "CDMA_SUBSCRIPTION_" }, value = { CDMA_SUBSCRIPTION_UNKNOWN, CDMA_SUBSCRIPTION_RUIM_SIM, @@ -11965,22 +12129,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; @@ -12001,8 +12174,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -12041,8 +12217,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -13766,8 +13945,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaPrlVersion() { @@ -13781,8 +13963,10 @@ public class TelephonyManager { * * @param subId the subscription ID that this request applies to. * @return PRLVersion or null if error. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public String getCdmaPrlVersion(int subId) { try { ITelephony service = getITelephony(); @@ -14948,7 +15132,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. @@ -14970,7 +15157,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. @@ -15077,7 +15267,10 @@ public class TelephonyManager { | NETWORK_TYPE_BITMASK_NR | NETWORK_TYPE_BITMASK_NB_IOT_NTN; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated public static final long NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2 = NETWORK_TYPE_BITMASK_CDMA | NETWORK_TYPE_BITMASK_1xRTT | NETWORK_TYPE_BITMASK_EVDO_0 diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java index 02429b5c2a2c..8fccf6505c0b 100644 --- a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java +++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java @@ -16,12 +16,15 @@ package android.telephony.cdma; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -34,18 +37,36 @@ import java.lang.annotation.RetentionPolicy; * containing an array of these objects to update its list of cell broadcast service categories * to display. * + * @deprecated Legacy CDMA is unsupported. * {@hide} */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated @SystemApi public final class CdmaSmsCbProgramData implements Parcelable { - /** Delete the specified service category from the list of enabled categories. */ + /** + * Delete the specified service category from the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_DELETE_CATEGORY = 0; - /** Add the specified service category to the list of enabled categories. */ + /** + * Add the specified service category to the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_ADD_CATEGORY = 1; - /** Clear all service categories from the list of enabled categories. */ + /** + * Clear all service categories from the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_CLEAR_CATEGORIES = 2; /** @hide */ @@ -59,23 +80,53 @@ public final class CdmaSmsCbProgramData implements Parcelable { public @interface Operation {} // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1 - /** Indicates a presidential-level alert */ + /** + * Indicates a presidential-level alert + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 0x1000; - /** Indicates an extreme threat to life and property */ + /** + * Indicates an extreme threat to life and property + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_EXTREME_THREAT = 0x1001; - /** Indicates an severe threat to life and property */ + /** + * Indicates an severe threat to life and property + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_SEVERE_THREAT = 0x1002; - /** Indicates an AMBER child abduction emergency */ + /** + * Indicates an AMBER child abduction emergency + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003; - /** Indicates a CMAS test message */ + /** + * Indicates a CMAS test message + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_TEST_MESSAGE = 0x1004; - /** The last reserved value of a CMAS service category according to 3GPP C.R1001 table - * 9.3.3-1. */ + /** + * The last reserved value of a CMAS service category according to 3GPP C.R1001 table + * 9.3.3-1. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 0x10ff; /** @hide */ @@ -177,7 +228,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written (ignored). + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mOperation); @@ -192,7 +246,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * Returns the service category operation, e.g. {@link #OPERATION_ADD_CATEGORY}. * * @return the service category operation + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public @Operation int getOperation() { return mOperation; } @@ -203,7 +260,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * 0x10FF are supported. * * @return a 16-bit CDMA service category value + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public @Category int getCategory() { return mCategory; } @@ -255,7 +315,11 @@ public final class CdmaSmsCbProgramData implements Parcelable { /** * Describe the kinds of special objects contained in the marshalled representation. * @return a bitmask indicating this Parcelable contains no special objects + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public int describeContents() { return 0; @@ -263,7 +327,11 @@ public final class CdmaSmsCbProgramData implements Parcelable { /** * Creator for unparcelling objects. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @NonNull public static final Parcelable.Creator<CdmaSmsCbProgramData> CREATOR = new Parcelable.Creator<CdmaSmsCbProgramData>() { diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 8925a9e82942..76f83ee49dcd 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -37,6 +38,8 @@ import android.telephony.ims.aidl.IRcsUceControllerCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.util.Log; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -226,8 +229,11 @@ public class RcsUceAdapter { /** * A capability update has been requested due to moving to eHRPD. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index da7669fd81ad..74d9204e9c84 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -416,6 +416,8 @@ interface ITelephony { * Returns the CDMA ERI icon index to display * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconIndex(String callingPackage, String callingFeatureId); @@ -424,6 +426,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -434,6 +438,8 @@ interface ITelephony { * 1 - FLASHING * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconMode(String callingPackage, String callingFeatureId); @@ -444,6 +450,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconModeForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -452,6 +460,8 @@ interface ITelephony { * Returns the CDMA ERI text, * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaEriText(String callingPackage, String callingFeatureId); @@ -460,6 +470,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaEriTextForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -779,6 +791,8 @@ interface ITelephony { * * @param itemID the ID of the item to read. * @return the NV item as a String, or null on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ String nvReadItem(int itemID); @@ -789,6 +803,8 @@ interface ITelephony { * @param itemID the ID of the item to read. * @param itemValue the value to write, as a String. * @return true on success; false on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean nvWriteItem(int itemID, String itemValue); @@ -798,6 +814,8 @@ interface ITelephony { * * @param preferredRoamingList byte array containing the new PRL. * @return true on success; false on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean nvWriteCdmaPrl(in byte[] preferredRoamingList); @@ -811,6 +829,8 @@ interface ITelephony { * * @param slotIndex - device slot. * @return {@code true} on success; {@code false} on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean resetModemConfig(int slotIndex); @@ -1041,12 +1061,16 @@ interface ITelephony { /** * Return MDN string for CDMA phone. * @param subId user preferred subId. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaMdn(int subId); /** * Return MIN string for CDMA phone. * @param subId user preferred subId. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaMin(int subId); @@ -1495,13 +1519,14 @@ interface ITelephony { String getEsn(int subId); /** - * Return the Preferred Roaming List Version - * - * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission - * @param subId the subscription ID that this request applies to. - * @return PRLVersion or null if error. - * @hide - */ + * Return the Preferred Roaming List Version + * + * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission + * @param subId the subscription ID that this request applies to. + * @return PRLVersion or null if error. + * @hide + * @deprecated Legacy CDMA is unsupported. + */ String getCdmaPrlVersion(int subId); /** @@ -1804,6 +1829,8 @@ interface ITelephony { * * @param the subscription id. * @return the roaming mode for CDMA phone. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaRoamingMode(int subId); @@ -1814,6 +1841,8 @@ interface ITelephony { * @param subId the subscription id. * @param mode the roaming mode should be set. * @return {@code true} if successed. + * + * @deprecated Legacy CDMA is unsupported. */ boolean setCdmaRoamingMode(int subId, int mode); @@ -1822,6 +1851,8 @@ interface ITelephony { * * @param the subscription id. * @return the subscription mode for CDMA phone. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaSubscriptionMode(int subId); @@ -1832,6 +1863,8 @@ interface ITelephony { * @param subId the subscription id. * @param mode the subscription mode should be set. * @return {@code true} if successed. + * + * @deprecated Legacy CDMA is unsupported. */ boolean setCdmaSubscriptionMode(int subId, int mode); |