Merge "Cleaning up flag NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE" into main
diff --git a/Android.bp b/Android.bp
index 9cb3067..48f0928 100644
--- a/Android.bp
+++ b/Android.bp
@@ -399,6 +399,7 @@
"com.android.sysprop.foldlockbehavior",
"com.android.sysprop.view",
"framework-internal-utils",
+ "dynamic_instrumentation_manager_aidl-java",
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
diff --git a/core/api/current.txt b/core/api/current.txt
index 664b3dd..80928bf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -44280,6 +44280,8 @@
field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1
field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC = 0; // 0x0
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int CARRIER_ROAMING_NTN_CONNECT_MANUAL = 1; // 0x1
field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_ONLY = 0; // 0x0
field public static final int CROSS_SIM_SPN_FORMAT_CARRIER_NAME_WITH_BRANDING = 1; // 0x1
field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe
@@ -44350,11 +44352,14 @@
field public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array";
field public static final String KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL = "carrier_provisions_wifi_merged_networks_bool";
field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT = "carrier_roaming_ntn_connect_type_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT = "carrier_roaming_ntn_emergency_call_to_satellite_handover_type_int";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY = "carrier_roaming_satellite_default_services_int_array";
field public static final String KEY_CARRIER_SERVICE_NAME_STRING_ARRAY = "carrier_service_name_array";
field public static final String KEY_CARRIER_SERVICE_NUMBER_STRING_ARRAY = "carrier_service_number_array";
field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT = "carrier_supported_satellite_notification_hysteresis_sec_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle";
field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
@@ -44405,6 +44410,7 @@
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 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";
field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array";
field public static final String KEY_DISPLAY_CALL_STRENGTH_INDICATOR_BOOL = "display_call_strength_indicator_bool";
@@ -44417,6 +44423,8 @@
field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT = "emergency_call_to_satellite_t911_handover_timeout_millis_int";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL = "emergency_messaging_supported_bool";
field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int";
field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
field public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL = "enable_cross_sim_calling_on_opportunistic_data_bool";
@@ -44463,6 +44471,7 @@
field public static final String KEY_MMS_MAX_IMAGE_HEIGHT_INT = "maxImageHeight";
field public static final String KEY_MMS_MAX_IMAGE_WIDTH_INT = "maxImageWidth";
field public static final String KEY_MMS_MAX_MESSAGE_SIZE_INT = "maxMessageSize";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT = "mms_max_ntn_payload_size_bytes_int";
field public static final String KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT = "maxMessageTextSize";
field public static final String KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL = "enableMMSDeliveryReports";
field public static final String KEY_MMS_MMS_ENABLED_BOOL = "enabledMMS";
@@ -44501,6 +44510,7 @@
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG = "opportunistic_network_max_backoff_time_long";
field public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG = "opportunistic_network_ping_pong_time_long";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL = "override_wfc_roaming_mode_while_using_ntn_bool";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT = "parameters_used_for_ntn_lte_signal_bar_int";
field public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL = "ping_test_before_data_switch_bool";
field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
@@ -44519,6 +44529,7 @@
field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array";
field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL = "remove_satellite_plmn_in_manual_network_scan_bool";
field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
field public static final String KEY_RTT_AUTO_UPGRADE_BOOL = "rtt_auto_upgrade_bool";
@@ -44530,13 +44541,18 @@
field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = "satellite_data_support_mode_int";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING = "satellite_entitlement_app_name_string";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING = "satellite_information_redirect_url_string";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_NIDD_APN_NAME_STRING = "satellite_nidd_apn_name_string";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_esos_inactivity_timeout_sec_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_p2p_sms_inactivity_timeout_sec_int";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL = "satellite_roaming_p2p_sms_supported_bool";
field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT = "satellite_roaming_screen_off_inactivity_timeout_sec_int";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL = "satellite_roaming_turn_off_session_for_emergency_call_bool";
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";
@@ -44606,6 +44622,9 @@
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
field public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_ALL = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED = 0; // 0x0
field public static final int SERVICE_CLASS_NONE = 0; // 0x0
field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 30fe244..8954f8e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -138,6 +138,7 @@
field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT";
+ field @FlaggedApi("com.android.art.flags.executable_method_file_offsets") public static final String DYNAMIC_INSTRUMENTATION = "android.permission.DYNAMIC_INSTRUMENTATION";
field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE";
field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
@@ -18332,7 +18333,12 @@
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS = 7; // 0x7
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3; // 0x3
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5; // 0x5
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4; // 0x4
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int DATAGRAM_TYPE_SMS = 6; // 0x6
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DEVICE_HOLD_POSITION_LANDSCAPE_LEFT = 2; // 0x2
@@ -18352,6 +18358,7 @@
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2; // 0x2
field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0; // 0x0
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
@@ -18365,6 +18372,8 @@
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_CONNECTED = 7; // 0x7
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_MODEM_STATE_DISABLING_SATELLITE = 9; // 0x9
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_MODEM_STATE_ENABLING_SATELLITE = 8; // 0x8
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_LISTENING = 1; // 0x1
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_NOT_CONNECTED = 6; // 0x6
@@ -18372,11 +18381,16 @@
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_DISABLE_IN_PROGRESS = 28; // 0x1c
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS = 27; // 0x1b
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29; // 0x1d
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ERROR = 1; // 0x1
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_ILLEGAL_STATE = 23; // 0x17
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25; // 0x19
+ field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26; // 0x1a
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_RESULT_MODEM_TIMEOUT = 24; // 0x18
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 71623c5..cf5ebbaa3 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -28,6 +28,7 @@
exclude_srcs: [
"android/os/*MessageQueue/**/*.java",
"android/ranging/**/*.java",
+ ":dynamic_instrumentation_manager_aidl_sources",
],
visibility: ["//frameworks/base"],
}
@@ -120,6 +121,17 @@
}
filegroup {
+ name: "dynamic_instrumentation_manager_aidl_sources",
+ srcs: ["android/os/instrumentation/*.aidl"],
+}
+
+aidl_interface {
+ name: "dynamic_instrumentation_manager_aidl",
+ srcs: [":dynamic_instrumentation_manager_aidl_sources"],
+ unstable: true,
+}
+
+filegroup {
name: "framework-internal-display-sources",
srcs: ["com/android/internal/display/BrightnessSynchronizer.java"],
visibility: ["//frameworks/base/services/tests/mockingservicestests"],
@@ -685,16 +697,31 @@
// Generates com.android.internal.pm.RoSystemFeatures, optionally compiling in
// details about fixed system features defined by build flags. When disabled,
// the APIs are simply passthrough stubs with no meaningful side effects.
+// TODO(b/203143243): Implement the `--feature=` aggregation directly with a native soong module.
genrule {
name: "systemfeatures-gen-srcs",
cmd: "$(location systemfeatures-gen-tool) com.android.internal.pm.RoSystemFeatures " +
// --readonly=false (default) makes the codegen an effective no-op passthrough API.
" --readonly=" + gen_readonly_feature_apis +
- // For now, only export "android.hardware.type.*" system features APIs.
- // TODO(b/203143243): Use an intermediate soong var that aggregates all declared
- // RELEASE_SYSTEM_FEATURE_* declarations into a single arg.
- " --feature-apis=AUTOMOTIVE,WATCH,TELEVISION,EMBEDDED,PC" +
- " > $(out)",
+ " --feature=AUTOMOTIVE:" + select(release_flag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE"), {
+ any @ value: value,
+ default: "",
+ }) + " --feature=EMBEDDED:" + select(release_flag("RELEASE_SYSTEM_FEATURE_EMBEDDED"), {
+ any @ value: value,
+ default: "",
+ }) + " --feature=LEANBACK:" + select(release_flag("RELEASE_SYSTEM_FEATURE_LEANBACK"), {
+ any @ value: value,
+ default: "",
+ }) + " --feature=PC:" + select(release_flag("RELEASE_SYSTEM_FEATURE_PC"), {
+ any @ value: value,
+ default: "",
+ }) + " --feature=TELEVISION:" + select(release_flag("RELEASE_SYSTEM_FEATURE_TELEVISION"), {
+ any @ value: value,
+ default: "",
+ }) + " --feature=WATCH:" + select(release_flag("RELEASE_SYSTEM_FEATURE_WATCH"), {
+ any @ value: value,
+ default: "",
+ }) + " > $(out)",
out: [
"RoSystemFeatures.java",
],
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 186f7b3..6086f24 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6802,6 +6802,12 @@
public static final String MEDIA_QUALITY_SERVICE = "media_quality";
/**
+ * Service to perform operations needed for dynamic instrumentation.
+ * @hide
+ */
+ public static final String DYNAMIC_INSTRUMENTATION_SERVICE = "dynamic_instrumentation";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index ef59e0a..93ef5c3 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -45,7 +45,7 @@
* </p>
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("CursorWindow_host")
+@RavenwoodRedirectionClass("CursorWindow_ravenwood")
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
diff --git a/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java b/core/java/android/database/CursorWindow_ravenwood.java
similarity index 89%
rename from ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java
rename to core/java/android/database/CursorWindow_ravenwood.java
index e21a9cd..990ec5e 100644
--- a/ravenwood/runtime-helper-src/framework/android/database/CursorWindow_host.java
+++ b/core/java/android/database/CursorWindow_ravenwood.java
@@ -17,6 +17,7 @@
import android.database.sqlite.SQLiteException;
import android.os.Parcel;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import android.util.Base64;
import java.text.DecimalFormat;
@@ -26,9 +27,10 @@
import java.util.HashMap;
import java.util.List;
-public class CursorWindow_host {
+@RavenwoodKeepWholeClass
+class CursorWindow_ravenwood {
- private static final HashMap<Long, CursorWindow_host> sInstances = new HashMap<>();
+ private static final HashMap<Long, CursorWindow_ravenwood> sInstances = new HashMap<>();
private static long sNextId = 1;
private String mName;
@@ -41,7 +43,7 @@
private final List<Row> mRows = new ArrayList<>();
public static long nativeCreate(String name, int cursorWindowSize) {
- CursorWindow_host instance = new CursorWindow_host();
+ CursorWindow_ravenwood instance = new CursorWindow_ravenwood();
instance.mName = name;
long instanceId = sNextId++;
sInstances.put(instanceId, instance);
@@ -66,7 +68,7 @@
}
public static boolean nativeAllocRow(long windowPtr) {
- CursorWindow_host instance = sInstances.get(windowPtr);
+ CursorWindow_ravenwood instance = sInstances.get(windowPtr);
Row row = new Row();
row.mFields = new String[instance.mColumnNum];
row.mTypes = new int[instance.mColumnNum];
@@ -76,7 +78,7 @@
}
private static boolean put(long windowPtr, String value, int type, int row, int column) {
- CursorWindow_host instance = sInstances.get(windowPtr);
+ CursorWindow_ravenwood instance = sInstances.get(windowPtr);
if (row >= instance.mRows.size() || column >= instance.mColumnNum) {
return false;
}
@@ -87,7 +89,7 @@
}
public static int nativeGetType(long windowPtr, int row, int column) {
- CursorWindow_host instance = sInstances.get(windowPtr);
+ CursorWindow_ravenwood instance = sInstances.get(windowPtr);
if (row >= instance.mRows.size() || column >= instance.mColumnNum) {
return Cursor.FIELD_TYPE_NULL;
}
@@ -101,7 +103,7 @@
}
public static String nativeGetString(long windowPtr, int row, int column) {
- CursorWindow_host instance = sInstances.get(windowPtr);
+ CursorWindow_ravenwood instance = sInstances.get(windowPtr);
if (row >= instance.mRows.size() || column >= instance.mColumnNum) {
return null;
}
@@ -164,7 +166,7 @@
}
public static void nativeWriteToParcel(long windowPtr, Parcel parcel) {
- CursorWindow_host window = sInstances.get(windowPtr);
+ CursorWindow_ravenwood window = sInstances.get(windowPtr);
parcel.writeString(window.mName);
parcel.writeInt(window.mColumnNum);
parcel.writeInt(window.mRows.size());
@@ -176,7 +178,7 @@
public static long nativeCreateFromParcel(Parcel parcel) {
long windowPtr = nativeCreate(null, 0);
- CursorWindow_host window = sInstances.get(windowPtr);
+ CursorWindow_ravenwood window = sInstances.get(windowPtr);
window.mName = parcel.readString();
window.mColumnNum = parcel.readInt();
int rowCount = parcel.readInt();
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index acda0c5..69bd668 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -55,7 +55,7 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("MessageQueue_host")
+@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG_L = "LegacyMessageQueue";
private static final String TAG_C = "ConcurrentMessageQueue";
diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
index 9db88d1..c2a47d7 100644
--- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
+++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
@@ -54,7 +54,7 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("MessageQueue_host")
+@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "ConcurrentMessageQueue";
private static final boolean DEBUG = false;
diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
index 9f7b0b7..cae82d0 100644
--- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java
+++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
@@ -45,7 +45,7 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("MessageQueue_host")
+@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
private static final boolean DEBUG = false;
diff --git a/core/java/android/os/LockedMessageQueue/MessageQueue.java b/core/java/android/os/LockedMessageQueue/MessageQueue.java
index f3eec13..2401f3d 100644
--- a/core/java/android/os/LockedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/LockedMessageQueue/MessageQueue.java
@@ -48,7 +48,7 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("MessageQueue_host")
+@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "LockedMessageQueue";
private static final boolean DEBUG = false;
diff --git a/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java b/core/java/android/os/MessageQueue_ravenwood.java
similarity index 87%
rename from ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java
rename to core/java/android/os/MessageQueue_ravenwood.java
index 1b63adc..4033707 100644
--- a/ravenwood/runtime-helper-src/framework/android/os/MessageQueue_host.java
+++ b/core/java/android/os/MessageQueue_ravenwood.java
@@ -16,13 +16,16 @@
package android.os;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
-public class MessageQueue_host {
+@RavenwoodKeepWholeClass
+class MessageQueue_ravenwood {
private static final AtomicLong sNextId = new AtomicLong(1);
- private static final Map<Long, MessageQueue_host> sInstances = new ConcurrentHashMap<>();
+ private static final Map<Long, MessageQueue_ravenwood> sInstances = new ConcurrentHashMap<>();
private boolean mDeleted = false;
@@ -37,8 +40,8 @@
}
}
- private static MessageQueue_host getInstance(long id) {
- MessageQueue_host q = sInstances.get(id);
+ private static MessageQueue_ravenwood getInstance(long id) {
+ MessageQueue_ravenwood q = sInstances.get(id);
if (q == null) {
throw new RuntimeException("MessageQueue doesn't exist with id=" + id);
}
@@ -48,7 +51,7 @@
public static long nativeInit() {
final long id = sNextId.getAndIncrement();
- final MessageQueue_host q = new MessageQueue_host();
+ final MessageQueue_ravenwood q = new MessageQueue_ravenwood();
sInstances.put(id, q);
return id;
}
diff --git a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
index db323dc..435c34f 100644
--- a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
+++ b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
@@ -52,7 +52,7 @@
* {@link Looper#myQueue() Looper.myQueue()}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("MessageQueue_host")
+@RavenwoodRedirectionClass("MessageQueue_ravenwood")
public final class MessageQueue {
private static final String TAG = "SemiConcurrentMessageQueue";
private static final boolean DEBUG = false;
diff --git a/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl b/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl
new file mode 100644
index 0000000..dbe5489
--- /dev/null
+++ b/core/java/android/os/instrumentation/ExecutableMethodFileOffsets.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os.instrumentation;
+
+/**
+ * Represents the location of the code for a compiled method within a process'
+ * memory.
+ * {@hide}
+ */
+@JavaDerive(toString=true)
+parcelable ExecutableMethodFileOffsets {
+ /**
+ * The OS path of the containing file (could be virtual).
+ */
+ @utf8InCpp String containerPath;
+ /**
+ * The offset of the containing file within the process' memory.
+ */
+ long containerOffset;
+ /**
+ * The offset of the method within the containing file.
+ */
+ long methodOffset;
+}
diff --git a/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl
new file mode 100644
index 0000000..c45c51d
--- /dev/null
+++ b/core/java/android/os/instrumentation/IDynamicInstrumentationManager.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.instrumentation;
+
+import android.os.instrumentation.ExecutableMethodFileOffsets;
+import android.os.instrumentation.MethodDescriptor;
+import android.os.instrumentation.TargetProcess;
+
+/**
+ * System private API for managing the dynamic attachment of instrumentation.
+ *
+ * {@hide}
+ */
+interface IDynamicInstrumentationManager {
+ /** Provides ART metadata about the described compiled method within the target process */
+ @PermissionManuallyEnforced
+ @nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets(
+ in TargetProcess targetProcess, in MethodDescriptor methodDescriptor);
+}
diff --git a/core/java/android/os/instrumentation/MethodDescriptor.aidl b/core/java/android/os/instrumentation/MethodDescriptor.aidl
new file mode 100644
index 0000000..055d0ec
--- /dev/null
+++ b/core/java/android/os/instrumentation/MethodDescriptor.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.instrumentation;
+
+/**
+ * Represents a JVM method, where class fields that make up its signature.
+ * {@hide}
+ */
+@JavaDerive(toString=true)
+parcelable MethodDescriptor {
+ /**
+ * Fully qualified class in reverse.domain.Naming
+ */
+ @utf8InCpp String fullyQualifiedClassName;
+ /**
+ * Name of the method.
+ */
+ @utf8InCpp String methodName;
+ /**
+ * Fully qualified types of method parameters, or string representations if primitive e.g. "int".
+ */
+ @utf8InCpp String[] fullyQualifiedParameters;
+}
diff --git a/core/java/android/os/instrumentation/TargetProcess.aidl b/core/java/android/os/instrumentation/TargetProcess.aidl
new file mode 100644
index 0000000..e90780d
--- /dev/null
+++ b/core/java/android/os/instrumentation/TargetProcess.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.instrumentation;
+
+/**
+ * Addresses a process that would run on the device.
+ * Helps disambiguate targeted processes in cases of pid re-use.
+ * {@hide}
+ */
+@JavaDerive(toString=true)
+parcelable TargetProcess {
+ int uid;
+ int pid;
+ @utf8InCpp String processName;
+}
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index b3480ab..2931bd2 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -56,7 +56,7 @@
* @hide
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("LongArrayMultiStateCounter_host")
+@RavenwoodRedirectionClass("LongArrayMultiStateCounter_ravenwood")
public final class LongArrayMultiStateCounter implements Parcelable {
private static volatile NativeAllocationRegistry sRegistry;
private final int mStateCount;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
similarity index 98%
rename from ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java
rename to core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
index 90608f6..7030d8e 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongArrayMultiStateCounter_host.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java
@@ -18,6 +18,7 @@
import android.os.BadParcelableException;
import android.os.Parcel;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import java.util.Arrays;
import java.util.HashMap;
@@ -25,7 +26,8 @@
/**
* Native implementation substitutions for the LongArrayMultiStateCounter class.
*/
-public class LongArrayMultiStateCounter_host {
+@RavenwoodKeepWholeClass
+class LongArrayMultiStateCounter_ravenwood {
/**
* A reimplementation of {@link LongArrayMultiStateCounter}, only in
diff --git a/core/java/com/android/internal/os/LongMultiStateCounter.java b/core/java/com/android/internal/os/LongMultiStateCounter.java
index c386a86..ee855d5 100644
--- a/core/java/com/android/internal/os/LongMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongMultiStateCounter.java
@@ -60,7 +60,7 @@
* @hide
*/
@RavenwoodKeepWholeClass
-@RavenwoodRedirectionClass("LongMultiStateCounter_host")
+@RavenwoodRedirectionClass("LongMultiStateCounter_ravenwood")
public final class LongMultiStateCounter implements Parcelable {
private static NativeAllocationRegistry sRegistry;
diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java b/core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java
similarity index 97%
rename from ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java
rename to core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java
index 1d95aa1..42db37f 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/internal/os/LongMultiStateCounter_host.java
+++ b/core/java/com/android/internal/os/LongMultiStateCounter_ravenwood.java
@@ -18,13 +18,15 @@
import android.os.BadParcelableException;
import android.os.Parcel;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
import java.util.HashMap;
/**
* Native implementation substitutions for the LongMultiStateCounter class.
*/
-public class LongMultiStateCounter_host {
+@RavenwoodKeepWholeClass
+class LongMultiStateCounter_ravenwood {
/**
* A reimplementation of {@link com.android.internal.os.LongMultiStateCounter}, only in
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 73776f0..0e4e22b 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -172,6 +172,7 @@
"android.security.flags-aconfig",
"com.android.hardware.input.input-aconfig",
"aconfig_trade_in_mode_flags",
+ "art-aconfig-flags",
"ranging_aconfig_flags",
"aconfig_settingslib_flags",
],
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0e4eb94..d09802a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8524,6 +8524,16 @@
android:protectionLevel="signature|privileged"
android:featureFlag="com.android.tradeinmode.flags.enable_trade_in_mode" />
+ <!-- @SystemApi
+ @FlaggedApi(com.android.art.flags.Flags.FLAG_EXECUTABLE_METHOD_FILE_OFFSETS)
+ Ability to read program metadata and attach dynamic instrumentation.
+ <p>Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.DYNAMIC_INSTRUMENTATION"
+ android:protectionLevel="signature"
+ android:featureFlag="com.android.art.flags.executable_method_file_offsets" />
+
<!--
@TestApi
Signature permission reserved for testing. This should never be used to
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 7b96699..857df10 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -213,6 +213,8 @@
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="gpu_service" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="keystore" />
+ <assign-permission name="android.permission.DYNAMIC_INSTRUMENTATION" uid="uprobestats" />
+
<split-permission name="android.permission.ACCESS_FINE_LOCATION">
<new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
</split-permission>
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
index 501bedd..c2755ef 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
@@ -19,6 +19,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical"
+ android:clipChildren="false"
android:id="@+id/bubble_expanded_view">
<com.android.wm.shell.bubbles.bar.BubbleBarHandleView
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
index f1ecde4..7aca921 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_menu_view.xml
@@ -14,20 +14,18 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.wm.shell.bubbles.bar.BubbleBarMenuView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<com.android.wm.shell.bubbles.bar.BubbleBarMenuView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
+ android:clipToPadding="false"
android:minWidth="@dimen/bubble_bar_manage_menu_min_width"
android:orientation="vertical"
- android:elevation="@dimen/bubble_manage_menu_elevation"
- android:paddingTop="@dimen/bubble_bar_manage_menu_padding_top"
- android:paddingHorizontal="@dimen/bubble_bar_manage_menu_padding"
- android:paddingBottom="@dimen/bubble_bar_manage_menu_padding"
- android:clipToPadding="false">
+ android:visibility="invisible"
+ tools:visibility="visible">
<LinearLayout
android:id="@+id/bubble_bar_manage_menu_bubble_section"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 2a50e4d0..272dfec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -222,7 +222,7 @@
mHandleView.setAccessibilityDelegate(new HandleViewAccessibilityDelegate());
}
- mMenuViewController = new BubbleBarMenuViewController(mContext, this);
+ mMenuViewController = new BubbleBarMenuViewController(mContext, mHandleView, this);
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@Override
public void onMenuVisibilityChanged(boolean visible) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
index e781c07..712e41b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -17,17 +17,18 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Outline;
-import android.graphics.Path;
-import android.graphics.RectF;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewOutlineProvider;
import androidx.annotation.ColorInt;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.animation.IntProperty;
import androidx.core.content.ContextCompat;
import com.android.wm.shell.R;
@@ -37,14 +38,33 @@
*/
public class BubbleBarHandleView extends View {
private static final long COLOR_CHANGE_DURATION = 120;
- // Path used to draw the dots
- private final Path mPath = new Path();
+ /** Custom property to set handle color. */
+ private static final IntProperty<BubbleBarHandleView> HANDLE_COLOR = new IntProperty<>(
+ "handleColor") {
+ @Override
+ public void setValue(BubbleBarHandleView bubbleBarHandleView, int color) {
+ bubbleBarHandleView.setHandleColor(color);
+ }
+
+ @Override
+ public Integer get(BubbleBarHandleView bubbleBarHandleView) {
+ return bubbleBarHandleView.getHandleColor();
+ }
+ };
+
+ @VisibleForTesting
+ final Paint mHandlePaint = new Paint();
private final @ColorInt int mHandleLightColor;
private final @ColorInt int mHandleDarkColor;
- private @ColorInt int mCurrentColor;
+ private final ArgbEvaluator mArgbEvaluator = ArgbEvaluator.getInstance();
+ private final float mHandleHeight;
+ private final float mHandleWidth;
+ private float mCurrentHandleHeight;
+ private float mCurrentHandleWidth;
@Nullable
private ObjectAnimator mColorChangeAnim;
+ private @ColorInt int mRegionSamplerColor;
public BubbleBarHandleView(Context context) {
this(context, null /* attrs */);
@@ -61,30 +81,52 @@
public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- final int handleHeight = getResources().getDimensionPixelSize(
+ mHandlePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ mHandlePaint.setStyle(Paint.Style.FILL);
+ mHandlePaint.setColor(0);
+ mHandleHeight = getResources().getDimensionPixelSize(
R.dimen.bubble_bar_expanded_view_handle_height);
+ mHandleWidth = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_width);
mHandleLightColor = ContextCompat.getColor(getContext(),
R.color.bubble_bar_expanded_view_handle_light);
mHandleDarkColor = ContextCompat.getColor(getContext(),
R.color.bubble_bar_expanded_view_handle_dark);
-
- setClipToOutline(true);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- final int handleCenterY = view.getHeight() / 2;
- final int handleTop = handleCenterY - handleHeight / 2;
- final int handleBottom = handleTop + handleHeight;
- final int radius = handleHeight / 2;
- RectF handle = new RectF(/* left = */ 0, handleTop, view.getWidth(), handleBottom);
- mPath.reset();
- mPath.addRoundRect(handle, radius, radius, Path.Direction.CW);
- outline.setPath(mPath);
- }
- });
+ mCurrentHandleHeight = mHandleHeight;
+ mCurrentHandleWidth = mHandleWidth;
setContentDescription(getResources().getString(R.string.handle_text));
}
+ private void setHandleColor(int color) {
+ mHandlePaint.setColor(color);
+ invalidate();
+ }
+
+ private int getHandleColor() {
+ return mHandlePaint.getColor();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ float handleLeft = (getWidth() - mCurrentHandleWidth) / 2;
+ float handleRight = handleLeft + mCurrentHandleWidth;
+ float handleCenterY = (float) getHeight() / 2;
+ float handleTop = (int) (handleCenterY - mCurrentHandleHeight / 2);
+ float handleBottom = handleTop + mCurrentHandleHeight;
+ float cornerRadius = mCurrentHandleHeight / 2;
+ canvas.drawRoundRect(handleLeft, handleTop, handleRight, handleBottom, cornerRadius,
+ cornerRadius, mHandlePaint);
+ }
+
+ /** Sets handle width, height and color. Does not change the layout properties */
+ private void setHandleProperties(float width, float height, int color) {
+ mCurrentHandleHeight = height;
+ mCurrentHandleWidth = width;
+ mHandlePaint.setColor(color);
+ invalidate();
+ }
+
/**
* Updates the handle color.
*
@@ -94,15 +136,15 @@
*/
public void updateHandleColor(boolean isRegionDark, boolean animated) {
int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
- if (newColor == mCurrentColor) {
+ if (newColor == mRegionSamplerColor) {
return;
}
+ mRegionSamplerColor = newColor;
if (mColorChangeAnim != null) {
mColorChangeAnim.cancel();
}
- mCurrentColor = newColor;
if (animated) {
- mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
+ mColorChangeAnim = ObjectAnimator.ofArgb(this, HANDLE_COLOR, newColor);
mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -112,7 +154,39 @@
mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
mColorChangeAnim.start();
} else {
- setBackgroundColor(newColor);
+ setHandleColor(newColor);
}
}
+
+ /** Returns handle padding top. */
+ public int getHandlePaddingTop() {
+ return (getHeight() - getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_handle_height)) / 2;
+ }
+
+ /** Animates handle for the bubble menu. */
+ public void animateHandleForMenu(float progress, float widthDelta, float heightDelta,
+ int menuColor) {
+ float currentWidth = mHandleWidth + widthDelta * progress;
+ float currentHeight = mHandleHeight + heightDelta * progress;
+ int color = (int) mArgbEvaluator.evaluate(progress, mRegionSamplerColor, menuColor);
+ setHandleProperties(currentWidth, currentHeight, color);
+ setTranslationY(heightDelta * progress / 2);
+ }
+
+ /** Restores all the properties that were animated to the default values. */
+ public void restoreAnimationDefaults() {
+ setHandleProperties(mHandleWidth, mHandleHeight, mRegionSamplerColor);
+ setTranslationY(0);
+ }
+
+ /** Returns the handle height. */
+ public int getHandleHeight() {
+ return (int) mHandleHeight;
+ }
+
+ /** Returns the handle width. */
+ public int getHandleWidth() {
+ return (int) mHandleWidth;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
index 0ee20ef..99e2009 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuView.java
@@ -47,6 +47,10 @@
private ImageView mBubbleIconView;
private ImageView mBubbleDismissIconView;
private TextView mBubbleTitleView;
+ // The animation has three stages. Each stage transition lasts until the animation ends. In
+ // stage 1, the title item content fades in. In stage 2, the background of the option items
+ // fades in. In stage 3, the option item content fades in.
+ private static final int SHOW_MENU_STAGES_COUNT = 3;
public BubbleBarMenuView(Context context) {
this(context, null /* attrs */);
@@ -97,6 +101,35 @@
}
}
+ /** Animates the menu from the specified start scale. */
+ public void animateFromStartScale(float currentScale, float progress) {
+ int menuItemElevation = getResources().getDimensionPixelSize(
+ R.dimen.bubble_manage_menu_elevation);
+ setScaleX(currentScale);
+ setScaleY(currentScale);
+ setAlphaForTitleViews(progress);
+ mBubbleSectionView.setElevation(menuItemElevation * progress);
+ float actionsBackgroundAlpha = Math.max(0,
+ (progress - (float) 1 / SHOW_MENU_STAGES_COUNT) * (SHOW_MENU_STAGES_COUNT - 1));
+ float actionItemsAlpha = Math.max(0,
+ (progress - (float) 2 / SHOW_MENU_STAGES_COUNT) * SHOW_MENU_STAGES_COUNT);
+ mActionsSectionView.setAlpha(actionsBackgroundAlpha);
+ mActionsSectionView.setElevation(menuItemElevation * actionsBackgroundAlpha);
+ setMenuItemViewsAlpha(actionItemsAlpha);
+ }
+
+ private void setAlphaForTitleViews(float alpha) {
+ mBubbleIconView.setAlpha(alpha);
+ mBubbleTitleView.setAlpha(alpha);
+ mBubbleDismissIconView.setAlpha(alpha);
+ }
+
+ private void setMenuItemViewsAlpha(float alpha) {
+ for (int i = mActionsSectionView.getChildCount() - 1; i >= 0; i--) {
+ mActionsSectionView.getChildAt(i).setAlpha(alpha);
+ }
+ }
+
/** Update menu details with bubble info */
void updateInfo(Bubble bubble) {
if (bubble.getIcon() != null) {
@@ -153,6 +186,11 @@
return mBubbleSectionView.getAlpha();
}
+ /** Return title menu item height. */
+ public float getTitleItemHeight() {
+ return mBubbleSectionView.getHeight();
+ }
+
/**
* Menu action details used to create menu items
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
index 5148107..9dd0cae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -15,6 +15,9 @@
*/
package com.android.wm.shell.bubbles.bar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -26,13 +29,10 @@
import android.view.View;
import android.view.ViewGroup;
-import androidx.dynamicanimation.animation.DynamicAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
-
+import com.android.app.animation.Interpolators;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
-import com.android.wm.shell.shared.animation.PhysicsAnimator;
import java.util.ArrayList;
@@ -40,22 +40,26 @@
* Manages bubble bar expanded view menu presentation and animations
*/
class BubbleBarMenuViewController {
- private static final float MENU_INITIAL_SCALE = 0.5f;
+
+ private static final float WIDTH_SWAP_FRACTION = 0.4F;
+ private static final long MENU_ANIMATION_DURATION = 600;
+
private final Context mContext;
private final ViewGroup mRootView;
+ private final BubbleBarHandleView mHandleView;
private @Nullable Listener mListener;
private @Nullable Bubble mBubble;
private @Nullable BubbleBarMenuView mMenuView;
/** A transparent view used to intercept touches to collapse menu when presented */
private @Nullable View mScrimView;
- private @Nullable PhysicsAnimator<BubbleBarMenuView> mMenuAnimator;
- private PhysicsAnimator.SpringConfig mMenuSpringConfig;
+ private @Nullable ValueAnimator mMenuAnimator;
- BubbleBarMenuViewController(Context context, ViewGroup rootView) {
+
+ BubbleBarMenuViewController(Context context, BubbleBarHandleView handleView,
+ ViewGroup rootView) {
mContext = context;
mRootView = rootView;
- mMenuSpringConfig = new PhysicsAnimator.SpringConfig(
- SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
+ mHandleView = handleView;
}
/** Tells if the menu is visible or being animated */
@@ -81,20 +85,21 @@
if (mMenuView == null || mScrimView == null) {
setupMenu();
}
- cancelAnimations();
- mMenuView.setVisibility(View.VISIBLE);
- mScrimView.setVisibility(View.VISIBLE);
- Runnable endActions = () -> {
- mMenuView.getChildAt(0).requestAccessibilityFocus();
- if (mListener != null) {
- mListener.onMenuVisibilityChanged(true /* isShown */);
+ runOnMenuIsMeasured(() -> {
+ mMenuView.setVisibility(View.VISIBLE);
+ mScrimView.setVisibility(View.VISIBLE);
+ Runnable endActions = () -> {
+ mMenuView.getChildAt(0).requestAccessibilityFocus();
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(true /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(true /* show */, endActions);
+ } else {
+ endActions.run();
}
- };
- if (animated) {
- animateTransition(true /* show */, endActions);
- } else {
- endActions.run();
- }
+ });
}
/**
@@ -103,18 +108,30 @@
*/
void hideMenu(boolean animated) {
if (mMenuView == null || mScrimView == null) return;
- cancelAnimations();
- Runnable endActions = () -> {
- mMenuView.setVisibility(View.GONE);
- mScrimView.setVisibility(View.GONE);
- if (mListener != null) {
- mListener.onMenuVisibilityChanged(false /* isShown */);
+ runOnMenuIsMeasured(() -> {
+ Runnable endActions = () -> {
+ mHandleView.restoreAnimationDefaults();
+ mMenuView.setVisibility(View.GONE);
+ mScrimView.setVisibility(View.GONE);
+ mHandleView.setVisibility(View.VISIBLE);
+ if (mListener != null) {
+ mListener.onMenuVisibilityChanged(false /* isShown */);
+ }
+ };
+ if (animated) {
+ animateTransition(false /* show */, endActions);
+ } else {
+ endActions.run();
}
- };
- if (animated) {
- animateTransition(false /* show */, endActions);
+ });
+ }
+
+ private void runOnMenuIsMeasured(Runnable action) {
+ if (mMenuView.getWidth() == 0 || mMenuView.getHeight() == 0) {
+ // the menu view is not yet measured, postpone showing the animation
+ mMenuView.post(() -> runOnMenuIsMeasured(action));
} else {
- endActions.run();
+ action.run();
}
}
@@ -125,24 +142,63 @@
*/
private void animateTransition(boolean show, Runnable endActions) {
if (mMenuView == null) return;
- mMenuAnimator = PhysicsAnimator.getInstance(mMenuView);
- mMenuAnimator.setDefaultSpringConfig(mMenuSpringConfig);
- mMenuAnimator
- .spring(DynamicAnimation.ALPHA, show ? 1f : 0f)
- .spring(DynamicAnimation.SCALE_Y, show ? 1f : MENU_INITIAL_SCALE)
- .withEndActions(() -> {
- mMenuAnimator = null;
- endActions.run();
- })
- .start();
+ float startValue = show ? 0 : 1;
+ if (mMenuAnimator != null && mMenuAnimator.isRunning()) {
+ startValue = (float) mMenuAnimator.getAnimatedValue();
+ mMenuAnimator.cancel();
+ }
+ ValueAnimator showMenuAnimation = ValueAnimator.ofFloat(startValue, show ? 1 : 0);
+ showMenuAnimation.setDuration(MENU_ANIMATION_DURATION);
+ showMenuAnimation.setInterpolator(Interpolators.EMPHASIZED);
+ showMenuAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mMenuAnimator = null;
+ endActions.run();
+ }
+ });
+ mMenuAnimator = showMenuAnimation;
+ setupAnimatorListener(showMenuAnimation);
+ showMenuAnimation.start();
}
- /** Cancel running animations */
- private void cancelAnimations() {
- if (mMenuAnimator != null) {
- mMenuAnimator.cancel();
- mMenuAnimator = null;
+ /** Setup listener that orchestrates the animation. */
+ private void setupAnimatorListener(ValueAnimator showMenuAnimation) {
+ // Getting views properties start values
+ int widthDiff = mMenuView.getWidth() - mHandleView.getHandleWidth();
+ int handleHeight = mHandleView.getHandleHeight();
+ float targetWidth = mHandleView.getHandleWidth() + widthDiff * WIDTH_SWAP_FRACTION;
+ float targetHeight = targetWidth * mMenuView.getTitleItemHeight() / mMenuView.getWidth();
+ int menuColor;
+ try (TypedArray ta = mContext.obtainStyledAttributes(new int[]{
+ com.android.internal.R.attr.materialColorSurfaceBright,
+ })) {
+ menuColor = ta.getColor(0, Color.WHITE);
}
+ // Calculating deltas
+ float swapScale = targetWidth / mMenuView.getWidth();
+ float handleWidthDelta = targetWidth - mHandleView.getHandleWidth();
+ float handleHeightDelta = targetHeight - handleHeight;
+ // Setting update listener that will orchestrate the animation
+ showMenuAnimation.addUpdateListener(animator -> {
+ float animationProgress = (float) animator.getAnimatedValue();
+ boolean showHandle = animationProgress <= WIDTH_SWAP_FRACTION;
+ mHandleView.setVisibility(showHandle ? View.VISIBLE : View.GONE);
+ mMenuView.setVisibility(showHandle ? View.GONE : View.VISIBLE);
+ if (showHandle) {
+ float handleAnimationProgress = animationProgress / WIDTH_SWAP_FRACTION;
+ mHandleView.animateHandleForMenu(handleAnimationProgress, handleWidthDelta,
+ handleHeightDelta, menuColor);
+ } else {
+ mMenuView.setTranslationY(mHandleView.getHandlePaddingTop());
+ mMenuView.setPivotY(0);
+ mMenuView.setPivotX((float) mMenuView.getWidth() / 2);
+ float menuAnimationProgress =
+ (animationProgress - WIDTH_SWAP_FRACTION) / (1 - WIDTH_SWAP_FRACTION);
+ float currentMenuScale = swapScale + (1 - swapScale) * menuAnimationProgress;
+ mMenuView.animateFromStartScale(currentMenuScale, menuAnimationProgress);
+ }
+ });
}
/** Sets up and inflate menu views */
@@ -150,9 +206,6 @@
// Menu view setup
mMenuView = (BubbleBarMenuView) LayoutInflater.from(mContext).inflate(
R.layout.bubble_bar_menu_view, mRootView, false);
- mMenuView.setAlpha(0f);
- mMenuView.setPivotY(0f);
- mMenuView.setScaleY(MENU_INITIAL_SCALE);
mMenuView.setOnCloseListener(() -> hideMenu(true /* animated */));
if (mBubble != null) {
mMenuView.updateInfo(mBubble);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index b27c428..0154d04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -45,12 +45,17 @@
}
/**
- * Set the callback when {@link PipTaskOrganizer#isInPip()} state is changed.
+ * Set the callback when isInPip state is changed.
*
- * @param callback The callback accepts the result of {@link PipTaskOrganizer#isInPip()}
- * when it's changed.
+ * @param callback The callback accepts the state of isInPip when it's changed.
*/
- default void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {}
+ default void addOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {}
+
+ /**
+ * Remove the callback when isInPip state is changed.
+ * @param callback The callback accepts the state of isInPip when it's changed.
+ */
+ default void removeOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {}
/**
* Called when showing Pip menu.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 7f61186..588b887 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -104,6 +104,7 @@
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -215,7 +216,7 @@
private boolean mIsKeyguardShowingOrAnimating;
- private Consumer<Boolean> mOnIsInPipStateChangedListener;
+ private final List<Consumer<Boolean>> mOnIsInPipStateChangedListeners = new ArrayList<>();
@VisibleForTesting
interface PipAnimationListener {
@@ -501,11 +502,11 @@
false /* saveRestoreSnapFraction */);
});
mPipTransitionState.addOnPipTransitionStateChangedListener((oldState, newState) -> {
- if (mOnIsInPipStateChangedListener != null) {
- final boolean wasInPip = PipTransitionState.isInPip(oldState);
- final boolean nowInPip = PipTransitionState.isInPip(newState);
- if (nowInPip != wasInPip) {
- mOnIsInPipStateChangedListener.accept(nowInPip);
+ final boolean wasInPip = PipTransitionState.isInPip(oldState);
+ final boolean nowInPip = PipTransitionState.isInPip(newState);
+ if (nowInPip != wasInPip) {
+ for (Consumer<Boolean> listener : mOnIsInPipStateChangedListeners) {
+ listener.accept(nowInPip);
}
}
});
@@ -960,13 +961,19 @@
mPipBoundsState.getLauncherState().setAppIconSizePx(iconSizePx);
}
- private void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
- mOnIsInPipStateChangedListener = callback;
- if (mOnIsInPipStateChangedListener != null) {
+ private void addOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ if (callback != null) {
+ mOnIsInPipStateChangedListeners.add(callback);
callback.accept(mPipTransitionState.isInPip());
}
}
+ private void removeOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ if (callback != null) {
+ mOnIsInPipStateChangedListeners.remove(callback);
+ }
+ }
+
private void setShelfHeightLocked(boolean visible, int height) {
final int shelfHeight = visible ? height : 0;
mPipBoundsState.setShelfVisibility(visible, shelfHeight);
@@ -1222,9 +1229,16 @@
}
@Override
- public void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
+ public void addOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
mMainExecutor.execute(() -> {
- PipController.this.setOnIsInPipStateChangedListener(callback);
+ PipController.this.addOnIsInPipStateChangedListener(callback);
+ });
+ }
+
+ @Override
+ public void removeOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ mMainExecutor.execute(() -> {
+ PipController.this.removeOnIsInPipStateChangedListener(callback);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index d3f537b..bc09183 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -21,6 +21,7 @@
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
@@ -66,6 +67,8 @@
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
@@ -94,7 +97,7 @@
private final PipTouchHandler mPipTouchHandler;
private final ShellExecutor mMainExecutor;
private final PipImpl mImpl;
- private Consumer<Boolean> mOnIsInPipStateChangedListener;
+ private final List<Consumer<Boolean>> mOnIsInPipStateChangedListeners = new ArrayList<>();
// Wrapper for making Binder calls into PiP animation listener hosted in launcher's Recents.
private PipAnimationListener mPipRecentsAnimationListener;
@@ -413,13 +416,13 @@
if (mPipTransitionState.isInSwipePipToHomeTransition()) {
mPipTransitionState.resetSwipePipToHomeState();
}
- if (mOnIsInPipStateChangedListener != null) {
- mOnIsInPipStateChangedListener.accept(true /* inPip */);
+ for (Consumer<Boolean> listener : mOnIsInPipStateChangedListeners) {
+ listener.accept(true /* inPip */);
}
break;
case PipTransitionState.EXITED_PIP:
- if (mOnIsInPipStateChangedListener != null) {
- mOnIsInPipStateChangedListener.accept(false /* inPip */);
+ for (Consumer<Boolean> listener : mOnIsInPipStateChangedListeners) {
+ listener.accept(false /* inPip */);
}
break;
}
@@ -451,13 +454,19 @@
mPipTransitionState.dump(pw, innerPrefix);
}
- private void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
- mOnIsInPipStateChangedListener = callback;
- if (mOnIsInPipStateChangedListener != null) {
+ private void addOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ if (callback != null) {
+ mOnIsInPipStateChangedListeners.add(callback);
callback.accept(mPipTransitionState.isInPip());
}
}
+ private void removeOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ if (callback != null) {
+ mOnIsInPipStateChangedListeners.remove(callback);
+ }
+ }
+
private void setLauncherAppIconSize(int iconSizePx) {
mPipBoundsState.getLauncherState().setAppIconSizePx(iconSizePx);
}
@@ -473,9 +482,16 @@
public void onSystemUiStateChanged(boolean isSysUiStateValid, long flag) {}
@Override
- public void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
+ public void addOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
mMainExecutor.execute(() -> {
- PipController.this.setOnIsInPipStateChangedListener(callback);
+ PipController.this.addOnIsInPipStateChangedListener(callback);
+ });
+ }
+
+ @Override
+ public void removeOnIsInPipStateChangedListener(@NonNull Consumer<Boolean> callback) {
+ mMainExecutor.execute(() -> {
+ PipController.this.removeOnIsInPipStateChangedListener(callback);
});
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
index d38b848..329a109 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java
@@ -16,9 +16,8 @@
package com.android.wm.shell.bubbles.bar;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
-import android.graphics.drawable.ColorDrawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -47,10 +46,9 @@
public void testUpdateHandleColor_lightBg() {
mHandleView.updateHandleColor(false /* isRegionDark */, false /* animated */);
- assertTrue(mHandleView.getClipToOutline());
- assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
- ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
- assertEquals(bgDrawable.getColor(),
+ assertFalse(mHandleView.getClipToOutline());
+ int handleColor = mHandleView.mHandlePaint.getColor();
+ assertEquals(handleColor,
ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_dark));
}
@@ -58,10 +56,9 @@
public void testUpdateHandleColor_darkBg() {
mHandleView.updateHandleColor(true /* isRegionDark */, false /* animated */);
- assertTrue(mHandleView.getClipToOutline());
- assertTrue(mHandleView.getBackground() instanceof ColorDrawable);
- ColorDrawable bgDrawable = (ColorDrawable) mHandleView.getBackground();
- assertEquals(bgDrawable.getColor(),
+ assertFalse(mHandleView.getClipToOutline());
+ int handleColor = mHandleView.mHandlePaint.getColor();
+ assertEquals(handleColor,
ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_light));
}
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 3eb99c3..da29c49 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -55,6 +55,7 @@
"surface_control_input_receiver.cpp",
"choreographer.cpp",
"configuration.cpp",
+ "dynamic_instrumentation_manager.cpp",
"hardware_buffer_jni.cpp",
"input.cpp",
"input_transfer_token.cpp",
@@ -100,6 +101,7 @@
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
"android.os.flags-aconfig-cc",
+ "dynamic_instrumentation_manager_aidl-cpp",
"libnativedisplay",
"libfmq",
],
diff --git a/native/android/dynamic_instrumentation_manager.cpp b/native/android/dynamic_instrumentation_manager.cpp
new file mode 100644
index 0000000..d9bacb1
--- /dev/null
+++ b/native/android/dynamic_instrumentation_manager.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ADynamicInstrumentationManager"
+#include <android/dynamic_instrumentation_manager.h>
+#include <android/os/instrumentation/ExecutableMethodFileOffsets.h>
+#include <android/os/instrumentation/IDynamicInstrumentationManager.h>
+#include <android/os/instrumentation/MethodDescriptor.h>
+#include <android/os/instrumentation/TargetProcess.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+#include <mutex>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::dynamicinstrumentationmanager {
+
+// Global instance of IDynamicInstrumentationManager, service is obtained only on first use.
+static std::mutex mLock;
+static sp<os::instrumentation::IDynamicInstrumentationManager> mService;
+
+sp<os::instrumentation::IDynamicInstrumentationManager> getService() {
+ std::lock_guard<std::mutex> scoped_lock(mLock);
+ if (mService == nullptr || !IInterface::asBinder(mService)->isBinderAlive()) {
+ sp<IBinder> binder =
+ defaultServiceManager()->waitForService(String16("dynamic_instrumentation"));
+ mService = interface_cast<os::instrumentation::IDynamicInstrumentationManager>(binder);
+ }
+ return mService;
+}
+
+} // namespace android::dynamicinstrumentationmanager
+
+using namespace android;
+using namespace dynamicinstrumentationmanager;
+
+struct ADynamicInstrumentationManager_TargetProcess {
+ uid_t uid;
+ uid_t pid;
+ std::string processName;
+
+ ADynamicInstrumentationManager_TargetProcess(uid_t uid, pid_t pid, const char* processName)
+ : uid(uid), pid(pid), processName(processName) {}
+};
+
+ADynamicInstrumentationManager_TargetProcess* ADynamicInstrumentationManager_TargetProcess_create(
+ uid_t uid, pid_t pid, const char* processName) {
+ return new ADynamicInstrumentationManager_TargetProcess(uid, pid, processName);
+}
+
+void ADynamicInstrumentationManager_TargetProcess_destroy(
+ ADynamicInstrumentationManager_TargetProcess* instance) {
+ delete instance;
+}
+
+struct ADynamicInstrumentationManager_MethodDescriptor {
+ std::string fqcn;
+ std::string methodName;
+ std::vector<std::string> fqParameters;
+
+ ADynamicInstrumentationManager_MethodDescriptor(const char* fqcn, const char* methodName,
+ const char* fullyQualifiedParameters[],
+ size_t numParameters)
+ : fqcn(fqcn), methodName(methodName) {
+ std::vector<std::string> fqParameters;
+ fqParameters.reserve(numParameters);
+ std::copy_n(fullyQualifiedParameters, numParameters, std::back_inserter(fqParameters));
+ this->fqParameters = std::move(fqParameters);
+ }
+};
+
+ADynamicInstrumentationManager_MethodDescriptor*
+ADynamicInstrumentationManager_MethodDescriptor_create(const char* fullyQualifiedClassName,
+ const char* methodName,
+ const char* fullyQualifiedParameters[],
+ size_t numParameters) {
+ return new ADynamicInstrumentationManager_MethodDescriptor(fullyQualifiedClassName, methodName,
+ fullyQualifiedParameters,
+ numParameters);
+}
+
+void ADynamicInstrumentationManager_MethodDescriptor_destroy(
+ ADynamicInstrumentationManager_MethodDescriptor* instance) {
+ delete instance;
+}
+
+struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets {
+ std::string containerPath;
+ uint64_t containerOffset;
+ uint64_t methodOffset;
+};
+
+ADynamicInstrumentationManager_ExecutableMethodFileOffsets*
+ADynamicInstrumentationManager_ExecutableMethodFileOffsets_create() {
+ return new ADynamicInstrumentationManager_ExecutableMethodFileOffsets();
+}
+
+const char* ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ return instance->containerPath.c_str();
+}
+
+uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ return instance->containerOffset;
+}
+
+uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ return instance->methodOffset;
+}
+
+void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* instance) {
+ delete instance;
+}
+
+int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
+ const ADynamicInstrumentationManager_TargetProcess* targetProcess,
+ const ADynamicInstrumentationManager_MethodDescriptor* methodDescriptor,
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets** out) {
+ android::os::instrumentation::TargetProcess targetProcessParcel;
+ targetProcessParcel.uid = targetProcess->uid;
+ targetProcessParcel.pid = targetProcess->pid;
+ targetProcessParcel.processName = targetProcess->processName;
+
+ android::os::instrumentation::MethodDescriptor methodDescriptorParcel;
+ methodDescriptorParcel.fullyQualifiedClassName = methodDescriptor->fqcn;
+ methodDescriptorParcel.methodName = methodDescriptor->methodName;
+ methodDescriptorParcel.fullyQualifiedParameters = methodDescriptor->fqParameters;
+
+ sp<os::instrumentation::IDynamicInstrumentationManager> service = getService();
+ if (service == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ std::optional<android::os::instrumentation::ExecutableMethodFileOffsets> offsets;
+ binder_status_t result =
+ service->getExecutableMethodFileOffsets(targetProcessParcel, methodDescriptorParcel,
+ &offsets)
+ .exceptionCode();
+ if (result != OK) {
+ return result;
+ }
+
+ if (offsets != std::nullopt) {
+ auto* value = new ADynamicInstrumentationManager_ExecutableMethodFileOffsets();
+ value->containerPath = offsets->containerPath;
+ value->containerOffset = offsets->containerOffset;
+ value->methodOffset = offsets->methodOffset;
+ *out = value;
+ } else {
+ *out = nullptr;
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/native/android/include_platform/android/dynamic_instrumentation_manager.h b/native/android/include_platform/android/dynamic_instrumentation_manager.h
new file mode 100644
index 0000000..6c46288
--- /dev/null
+++ b/native/android/include_platform/android/dynamic_instrumentation_manager.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#ifndef __ADYNAMICINSTRUMENTATIONMANAGER_H__
+#define __ADYNAMICINSTRUMENTATIONMANAGER_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct ADynamicInstrumentationManager_MethodDescriptor;
+typedef struct ADynamicInstrumentationManager_MethodDescriptor
+ ADynamicInstrumentationManager_MethodDescriptor;
+
+struct ADynamicInstrumentationManager_TargetProcess;
+typedef struct ADynamicInstrumentationManager_TargetProcess
+ ADynamicInstrumentationManager_TargetProcess;
+
+struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
+typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
+
+/**
+ * Initializes an ADynamicInstrumentationManager_TargetProcess. Caller must clean up when they are
+ * done with ADynamicInstrumentationManager_TargetProcess_destroy.
+ *
+ * @param uid of targeted process.
+ * @param pid of targeted process.
+ * @param processName to disambiguate from corner cases that may arise from pid reuse.
+ */
+ADynamicInstrumentationManager_TargetProcess* _Nonnull
+ ADynamicInstrumentationManager_TargetProcess_create(
+ uid_t uid, pid_t pid, const char* _Nonnull processName) __INTRODUCED_IN(36);
+/**
+ * Clean up an ADynamicInstrumentationManager_TargetProcess.
+ *
+ * @param instance returned from ADynamicInstrumentationManager_TargetProcess_create.
+ */
+void ADynamicInstrumentationManager_TargetProcess_destroy(
+ ADynamicInstrumentationManager_TargetProcess* _Nonnull instance) __INTRODUCED_IN(36);
+
+/**
+ * Initializes an ADynamicInstrumentationManager_MethodDescriptor. Caller must clean up when they
+ * are done with ADynamicInstrumentationManager_MethodDescriptor_Destroy.
+ *
+ * @param fullyQualifiedClassName fqcn of class containing the method.
+ * @param methodName
+ * @param fullyQualifiedParameters fqcn of parameters of the method's signature, or e.g. "int" for
+ * primitives.
+ * @param numParameters length of `fullyQualifiedParameters` array.
+ */
+ADynamicInstrumentationManager_MethodDescriptor* _Nonnull
+ ADynamicInstrumentationManager_MethodDescriptor_create(
+ const char* _Nonnull fullyQualifiedClassName, const char* _Nonnull methodName,
+ const char* _Nonnull fullyQualifiedParameters[_Nonnull], size_t numParameters)
+ __INTRODUCED_IN(36);
+/**
+ * Clean up an ADynamicInstrumentationManager_MethodDescriptor.
+ *
+ * @param instance returned from ADynamicInstrumentationManager_MethodDescriptor_create.
+ */
+void ADynamicInstrumentationManager_MethodDescriptor_destroy(
+ ADynamicInstrumentationManager_MethodDescriptor* _Nonnull instance) __INTRODUCED_IN(36);
+
+/**
+ * Get the containerPath calculated by
+ * ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @return The OS path of the containing file.
+ */
+const char* _Nullable ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ __INTRODUCED_IN(36);
+/**
+ * Get the containerOffset calculated by
+ * ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @return The offset of the containing file within the process' memory.
+ */
+uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ __INTRODUCED_IN(36);
+/**
+ * Get the methodOffset calculated by ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @param instance created with ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ * @return The offset of the method within the containing file.
+ */
+uint64_t ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ __INTRODUCED_IN(36);
+/**
+ * Clean up an ADynamicInstrumentationManager_ExecutableMethodFileOffsets.
+ *
+ * @param instance returned from ADynamicInstrumentationManager_getExecutableMethodFileOffsets.
+ */
+void ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy(
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull instance)
+ __INTRODUCED_IN(36);
+/**
+ * Provides ART metadata about the described java method within the target process.
+ *
+ * @param targetProcess describes for which process the data is requested.
+ * @param methodDescriptor describes the targeted method.
+ * @param out will be populated with the data if successful. A nullptr combined
+ * with an OK status means that the program method is defined, but the offset
+ * info was unavailable because it is not AOT compiled.
+ * @return status indicating success or failure. The values correspond to the `binder_exception_t`
+ * enum values from <android/binder_status.h>.
+ */
+int32_t ADynamicInstrumentationManager_getExecutableMethodFileOffsets(
+ const ADynamicInstrumentationManager_TargetProcess* _Nonnull targetProcess,
+ const ADynamicInstrumentationManager_MethodDescriptor* _Nonnull methodDescriptor,
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets* _Nonnull* _Nullable out)
+ __INTRODUCED_IN(36);
+
+__END_DECLS
+
+#endif // __ADYNAMICINSTRUMENTATIONMANAGER_H__
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index b025cb8..a046057 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -4,6 +4,15 @@
AActivityManager_removeUidImportanceListener; # systemapi introduced=31
AActivityManager_isUidActive; # systemapi introduced=31
AActivityManager_getUidImportance; # systemapi introduced=31
+ ADynamicInstrumentationManager_TargetProcess_create; # systemapi
+ ADynamicInstrumentationManager_TargetProcess_destroy; # systemapi
+ ADynamicInstrumentationManager_MethodDescriptor_create; # systemapi
+ ADynamicInstrumentationManager_MethodDescriptor_destroy; # systemapi
+ ADynamicInstrumentationManager_getExecutableMethodFileOffsets; # systemapi
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath; # systemapi
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset; # systemapi
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset; # systemapi
+ ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy; # systemapi
AAssetDir_close;
AAssetDir_getNextFileName;
AAssetDir_rewind;
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 24b91f9..0724410 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -959,6 +959,9 @@
<!-- Permission required for CTS test - CtsTelephonyTestCases -->
<uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE" />
+ <!-- Permission required for ExecutableMethodFileOffsetsTest -->
+ <uses-permission android:name="android.permission.DYNAMIC_INSTRUMENTATION" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index f49693a..80ac2fc 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -696,7 +696,8 @@
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
mTaskStackListener);
DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
- mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(null));
+ mPipOptional.ifPresent(pip -> pip.removeOnIsInPipStateChangedListener(
+ mOnIsInPipStateChangedListener));
try {
mWindowManagerService.unregisterSystemGestureExclusionListener(
@@ -720,7 +721,7 @@
mTaskStackListener);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
mUiThreadContext.getExecutor()::execute, mOnPropertiesChangedListener);
- mPipOptional.ifPresent(pip -> pip.setOnIsInPipStateChangedListener(
+ mPipOptional.ifPresent(pip -> pip.addOnIsInPipStateChangedListener(
mOnIsInPipStateChangedListener));
mDesktopModeOptional.ifPresent(
dm -> dm.addDesktopGestureExclusionRegionListener(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
index 9440a93..fb15795 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.dialog.dagger
+import com.android.systemui.volume.dialog.dagger.module.VolumeDialogModule
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
@@ -28,7 +29,7 @@
* [com.android.systemui.volume.dialog.VolumeDialogPlugin] and lives alongside it.
*/
@VolumeDialogScope
-@Subcomponent(modules = [])
+@Subcomponent(modules = [VolumeDialogModule::class])
interface VolumeDialogComponent {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
new file mode 100644
index 0000000..025e269
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.dagger.module
+
+import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepository
+import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+/** Dagger module for volume dialog code in the volume package */
+@Module
+interface VolumeDialogModule {
+
+ @Binds
+ fun bindVolumeDialogRingerFeedbackRepository(
+ ringerFeedbackRepository: VolumeDialogRingerFeedbackRepositoryImpl
+ ): VolumeDialogRingerFeedbackRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepository.kt
new file mode 100644
index 0000000..263972b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepository.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.ringer.data.repository
+
+import android.content.Context
+import com.android.systemui.Prefs
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+interface VolumeDialogRingerFeedbackRepository {
+
+ /** gets number of shown toasts */
+ suspend fun getToastCount(): Int
+
+ /** updates number of shown toasts */
+ suspend fun updateToastCount(toastCount: Int)
+}
+
+class VolumeDialogRingerFeedbackRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ @Background val backgroundDispatcher: CoroutineDispatcher,
+) : VolumeDialogRingerFeedbackRepository {
+
+ override suspend fun getToastCount(): Int =
+ withContext(backgroundDispatcher) {
+ return@withContext Prefs.getInt(
+ applicationContext,
+ Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT,
+ 0,
+ )
+ }
+
+ override suspend fun updateToastCount(toastCount: Int) {
+ withContext(backgroundDispatcher) {
+ Prefs.putInt(applicationContext, Prefs.Key.SEEN_RINGER_GUIDANCE_COUNT, toastCount + 1)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt
index 281e57f..b83613b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt
@@ -26,6 +26,7 @@
import com.android.systemui.plugins.VolumeDialogController
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
+import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepository
import com.android.systemui.volume.dialog.ringer.shared.model.VolumeDialogRingerModel
import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
import javax.inject.Inject
@@ -45,6 +46,7 @@
volumeDialogStateInteractor: VolumeDialogStateInteractor,
private val controller: VolumeDialogController,
private val audioSystemRepository: AudioSystemRepository,
+ private val ringerFeedbackRepository: VolumeDialogRingerFeedbackRepository,
) {
val ringerModel: Flow<VolumeDialogRingerModel> =
@@ -84,4 +86,12 @@
fun scheduleTouchFeedback() {
controller.scheduleTouchFeedback()
}
+
+ suspend fun getToastCount(): Int {
+ return ringerFeedbackRepository.getToastCount()
+ }
+
+ suspend fun updateToastCount(toastCount: Int) {
+ ringerFeedbackRepository.updateToastCount(toastCount)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
index d4da226..e040638 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt
@@ -16,17 +16,23 @@
package com.android.systemui.volume.dialog.ringer.ui.viewmodel
+import android.content.Context
import android.media.AudioAttributes
import android.media.AudioManager.RINGER_MODE_NORMAL
import android.media.AudioManager.RINGER_MODE_SILENT
import android.media.AudioManager.RINGER_MODE_VIBRATE
import android.os.VibrationEffect
+import android.widget.Toast
+import com.android.internal.R as internalR
+import com.android.settingslib.Utils
import com.android.settingslib.volume.shared.model.RingerMode
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.ringer.domain.VolumeDialogRingerInteractor
import com.android.systemui.volume.dialog.ringer.shared.model.VolumeDialogRingerModel
import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
@@ -40,26 +46,37 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+private const val SHOW_RINGER_TOAST_COUNT = 12
class VolumeDialogRingerDrawerViewModel
@AssistedInject
constructor(
+ @Application private val applicationContext: Context,
@VolumeDialog private val coroutineScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val interactor: VolumeDialogRingerInteractor,
private val vibrator: VibratorHelper,
private val volumeDialogLogger: VolumeDialogLogger,
+ private val visibilityInteractor: VolumeDialogVisibilityInteractor,
) {
private val drawerState = MutableStateFlow<RingerDrawerState>(RingerDrawerState.Initial)
val ringerViewModel: StateFlow<RingerViewModelState> =
combine(interactor.ringerModel, drawerState) { ringerModel, state ->
+ level = ringerModel.level
+ levelMax = ringerModel.levelMax
ringerModel.toViewModel(state)
}
.flowOn(backgroundDispatcher)
.stateIn(coroutineScope, SharingStarted.Eagerly, RingerViewModelState.Unavailable)
+ // Level and Maximum level of Ring Stream.
+ private var level = -1
+ private var levelMax = -1
+
// Vibration attributes.
private val sonificiationVibrationAttributes =
AudioAttributes.Builder()
@@ -71,8 +88,10 @@
if (drawerState.value is RingerDrawerState.Open) {
Events.writeEvent(Events.EVENT_RINGER_TOGGLE, ringerMode.value)
provideTouchFeedback(ringerMode)
+ maybeShowToast(ringerMode)
interactor.setRingerMode(ringerMode)
}
+ visibilityInteractor.resetDismissTimeout()
drawerState.value =
when (drawerState.value) {
is RingerDrawerState.Initial -> {
@@ -201,6 +220,46 @@
}
}
+ private fun maybeShowToast(ringerMode: RingerMode) {
+ coroutineScope.launch {
+ val seenToastCount = interactor.getToastCount()
+ if (seenToastCount > SHOW_RINGER_TOAST_COUNT) {
+ return@launch
+ }
+
+ val toastText =
+ when (ringerMode.value) {
+ RINGER_MODE_NORMAL -> {
+ if (level != -1 && levelMax != -1) {
+ applicationContext.getString(
+ R.string.volume_dialog_ringer_guidance_ring,
+ Utils.formatPercentage(level.toLong(), levelMax.toLong()),
+ )
+ } else {
+ null
+ }
+ }
+
+ RINGER_MODE_SILENT ->
+ applicationContext.getString(
+ internalR.string.volume_dialog_ringer_guidance_silent
+ )
+
+ RINGER_MODE_VIBRATE ->
+ applicationContext.getString(
+ internalR.string.volume_dialog_ringer_guidance_vibrate
+ )
+
+ else ->
+ applicationContext.getString(
+ internalR.string.volume_dialog_ringer_guidance_vibrate
+ )
+ }
+ toastText?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT).show() }
+ interactor.updateToastCount(seenToastCount)
+ }
+ }
+
@AssistedFactory
interface Factory {
fun create(): VolumeDialogRingerDrawerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 8039e00..073781e 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -271,6 +271,12 @@
// No op.
}
}, mSysUiMainExecutor);
+ pip.addOnIsInPipStateChangedListener((isInPip) -> {
+ if (!isInPip) {
+ mSysUiState.setFlag(SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING, false)
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
+ }
+ });
mSysUiState.addCallback(sysUiStateFlag -> {
mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/FakeVolumeDialogRingerFeedbackRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/FakeVolumeDialogRingerFeedbackRepository.kt
new file mode 100644
index 0000000..d42de1e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/FakeVolumeDialogRingerFeedbackRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.ringer.data.repository
+
+class FakeVolumeDialogRingerFeedbackRepository : VolumeDialogRingerFeedbackRepository {
+
+ private var seenToastCount = 0
+
+ override suspend fun getToastCount(): Int {
+ return seenToastCount
+ }
+
+ override suspend fun updateToastCount(toastCount: Int) {
+ seenToastCount = toastCount
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepositoryKosmos.kt
new file mode 100644
index 0000000..44371b4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/data/repository/VolumeDialogRingerFeedbackRepositoryKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.ringer.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.fakeVolumeDialogRingerFeedbackRepository by
+ Kosmos.Fixture { FakeVolumeDialogRingerFeedbackRepository() }
+val Kosmos.volumeDialogRingerFeedbackRepository by
+ Kosmos.Fixture { fakeVolumeDialogRingerFeedbackRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractorKosmos.kt
index 1addd91..a494d04 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractorKosmos.kt
@@ -21,6 +21,7 @@
import com.android.systemui.plugins.volumeDialogController
import com.android.systemui.volume.data.repository.audioSystemRepository
import com.android.systemui.volume.dialog.domain.interactor.volumeDialogStateInteractor
+import com.android.systemui.volume.dialog.ringer.data.repository.fakeVolumeDialogRingerFeedbackRepository
val Kosmos.volumeDialogRingerInteractor by
Kosmos.Fixture {
@@ -29,5 +30,6 @@
volumeDialogStateInteractor = volumeDialogStateInteractor,
controller = volumeDialogController,
audioSystemRepository = audioSystemRepository,
+ ringerFeedbackRepository = fakeVolumeDialogRingerFeedbackRepository,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
index db1c01a..c8ba551 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt
@@ -16,20 +16,24 @@
package com.android.systemui.volume.dialog.ringer.ui.viewmodel
+import android.content.applicationContext
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.ringer.domain.volumeDialogRingerInteractor
import com.android.systemui.volume.dialog.shared.volumeDialogLogger
val Kosmos.volumeDialogRingerDrawerViewModel by
Kosmos.Fixture {
VolumeDialogRingerDrawerViewModel(
+ applicationContext = applicationContext,
backgroundDispatcher = testDispatcher,
coroutineScope = applicationCoroutineScope,
interactor = volumeDialogRingerInteractor,
vibrator = vibratorHelper,
volumeDialogLogger = volumeDialogLogger,
+ visibilityInteractor = volumeDialogVisibilityInteractor,
)
}
diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
index 82be2c0..c196a09 100644
--- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
@@ -15,7 +15,9 @@
com.android.internal.os.BatteryStatsHistoryIterator
com.android.internal.os.Clock
com.android.internal.os.LongArrayMultiStateCounter
+com.android.internal.os.LongArrayMultiStateCounter_ravenwood
com.android.internal.os.LongMultiStateCounter
+com.android.internal.os.LongMultiStateCounter_ravenwood
com.android.internal.os.MonotonicClock
com.android.internal.os.PowerProfile
com.android.internal.os.PowerStats
@@ -143,6 +145,7 @@
android.os.Looper
android.os.Message
android.os.MessageQueue
+android.os.MessageQueue_ravenwood
android.os.PackageTagsList
android.os.Parcel
android.os.ParcelFileDescriptor
@@ -235,6 +238,7 @@
android.database.CursorIndexOutOfBoundsException
android.database.CursorJoiner
android.database.CursorWindow
+android.database.CursorWindow_ravenwood
android.database.CursorWrapper
android.database.DataSetObservable
android.database.DataSetObserver
@@ -370,4 +374,3 @@
com.android.server.compat.*
com.android.internal.compat.*
android.app.AppCompatCallbacks
-
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 974cba2..86d3ee6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -5071,6 +5071,11 @@
@EnforcePermission(MANAGE_ACCESSIBILITY)
public boolean isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info) {
isAccessibilityServiceWarningRequired_enforcePermission();
+ if (info == null) {
+ Log.e(LOG_TAG, "Called isAccessibilityServiceWarningRequired with null service info");
+ return true;
+ }
+
final ComponentName componentName = info.getComponentName();
// Warning is not required if the service is already enabled.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 3ccad160..7f482ac 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -158,6 +158,7 @@
"android.hardware.gnss-V2-java",
"android.hardware.vibrator-V3-java",
"app-compat-annotations",
+ "art_exported_aconfig_flags_lib",
"framework-tethering.stubs.module_lib",
"keepanno-annotations",
"service-art.stubs.system_server",
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index f2e2f65..5b4c033 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -1001,7 +1001,7 @@
try {
// Create an AIDL callback that can callback onHotplugEvent
mHdmiConnection.setCallback(new HdmiConnectionCallbackAidl(callback));
- } catch (RemoteException e) {
+ } catch (RemoteException | NullPointerException e) {
HdmiLogger.error("Couldn't initialise tv.hdmi callback : ", e);
}
}
@@ -1134,7 +1134,7 @@
i++;
}
return hdmiPortInfo;
- } catch (RemoteException e) {
+ } catch (RemoteException | NullPointerException e) {
HdmiLogger.error("Failed to get port information : ", e);
return null;
}
@@ -1144,7 +1144,7 @@
public boolean nativeIsConnected(int port) {
try {
return mHdmiConnection.isConnected(port);
- } catch (RemoteException e) {
+ } catch (RemoteException | NullPointerException e) {
HdmiLogger.error("Failed to get connection info : ", e);
return false;
}
@@ -1158,7 +1158,7 @@
HdmiLogger.error(
"Could not set HPD signal type for portId " + portId + " to " + signal
+ ". Error: ", sse.errorCode);
- } catch (RemoteException e) {
+ } catch (RemoteException | NullPointerException e) {
HdmiLogger.error(
"Could not set HPD signal type for portId " + portId + " to " + signal
+ ". Exception: ", e);
@@ -1169,7 +1169,7 @@
public int nativeGetHpdSignalType(int portId) {
try {
return mHdmiConnection.getHpdSignal(portId);
- } catch (RemoteException e) {
+ } catch (RemoteException | NullPointerException e) {
HdmiLogger.error(
"Could not get HPD signal type for portId " + portId + ". Exception: ", e);
return Constants.HDMI_HPD_TYPE_PHYSICAL;
diff --git a/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java
new file mode 100644
index 0000000..8ec7160
--- /dev/null
+++ b/services/core/java/com/android/server/os/instrumentation/DynamicInstrumentationManagerService.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os.instrumentation;
+
+import static android.Manifest.permission.DYNAMIC_INSTRUMENTATION;
+import static android.content.Context.DYNAMIC_INSTRUMENTATION_SERVICE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.PermissionManuallyEnforced;
+import android.content.Context;
+import android.os.instrumentation.ExecutableMethodFileOffsets;
+import android.os.instrumentation.IDynamicInstrumentationManager;
+import android.os.instrumentation.MethodDescriptor;
+import android.os.instrumentation.TargetProcess;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+
+import dalvik.system.VMDebug;
+
+import java.lang.reflect.Method;
+
+/**
+ * System private implementation of the {@link IDynamicInstrumentationManager interface}.
+ */
+public class DynamicInstrumentationManagerService extends SystemService {
+ public DynamicInstrumentationManagerService(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(DYNAMIC_INSTRUMENTATION_SERVICE, new BinderService());
+ }
+
+ private final class BinderService extends IDynamicInstrumentationManager.Stub {
+ @Override
+ @PermissionManuallyEnforced
+ public @Nullable ExecutableMethodFileOffsets getExecutableMethodFileOffsets(
+ @NonNull TargetProcess targetProcess, @NonNull MethodDescriptor methodDescriptor) {
+ if (!com.android.art.flags.Flags.executableMethodFileOffsets()) {
+ throw new UnsupportedOperationException();
+ }
+ getContext().enforceCallingOrSelfPermission(
+ DYNAMIC_INSTRUMENTATION, "Caller must have DYNAMIC_INSTRUMENTATION permission");
+
+ if (targetProcess.processName == null
+ || !targetProcess.processName.equals("system_server")) {
+ throw new UnsupportedOperationException(
+ "system_server is the only supported target process");
+ }
+
+ Method method = parseMethodDescriptor(
+ getClass().getClassLoader(), methodDescriptor);
+ VMDebug.ExecutableMethodFileOffsets location =
+ VMDebug.getExecutableMethodFileOffsets(method);
+
+ if (location == null) {
+ return null;
+ }
+
+ ExecutableMethodFileOffsets ret = new ExecutableMethodFileOffsets();
+ ret.containerPath = location.getContainerPath();
+ ret.containerOffset = location.getContainerOffset();
+ ret.methodOffset = location.getMethodOffset();
+ return ret;
+ }
+ }
+
+ @VisibleForTesting
+ static Method parseMethodDescriptor(ClassLoader classLoader,
+ @NonNull MethodDescriptor descriptor) {
+ try {
+ Class<?> javaClass = classLoader.loadClass(descriptor.fullyQualifiedClassName);
+ Class<?>[] parameters = new Class[descriptor.fullyQualifiedParameters.length];
+ for (int i = 0; i < descriptor.fullyQualifiedParameters.length; i++) {
+ String typeName = descriptor.fullyQualifiedParameters[i];
+ boolean isArrayType = typeName.endsWith("[]");
+ if (isArrayType) {
+ typeName = typeName.substring(0, typeName.length() - 2);
+ }
+ switch (typeName) {
+ case "boolean":
+ parameters[i] = isArrayType ? boolean.class.arrayType() : boolean.class;
+ break;
+ case "byte":
+ parameters[i] = isArrayType ? byte.class.arrayType() : byte.class;
+ break;
+ case "char":
+ parameters[i] = isArrayType ? char.class.arrayType() : char.class;
+ break;
+ case "short":
+ parameters[i] = isArrayType ? short.class.arrayType() : short.class;
+ break;
+ case "int":
+ parameters[i] = isArrayType ? int.class.arrayType() : int.class;
+ break;
+ case "long":
+ parameters[i] = isArrayType ? long.class.arrayType() : long.class;
+ break;
+ case "float":
+ parameters[i] = isArrayType ? float.class.arrayType() : float.class;
+ break;
+ case "double":
+ parameters[i] = isArrayType ? double.class.arrayType() : double.class;
+ break;
+ default:
+ parameters[i] = isArrayType ? classLoader.loadClass(typeName).arrayType()
+ : classLoader.loadClass(typeName);
+ }
+ }
+
+ return javaClass.getDeclaredMethod(descriptor.methodName, parameters);
+ } catch (ClassNotFoundException | NoSuchMethodException e) {
+ throw new IllegalArgumentException(
+ "The specified method cannot be found. Is this descriptor valid? "
+ + descriptor, e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index af2bb17..d538bb8 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -265,6 +265,7 @@
@Override
public void handleMessage(Message msg) {
+ Slog.d(TAG, "Package event received: " + msg.what);
switch (msg.what) {
case MSG_USAGE_EVENT_RECEIVED:
mService.handleUsageEvent(
@@ -326,6 +327,8 @@
return;
}
+ Slog.d(TAG, "handlePackageAdd: adding " + packageName + " from "
+ + userId + " and notifying callbacks");
initBackgroundInstalledPackages();
mBackgroundInstalledPackages.add(userId, packageName);
mCallbackHelper.notifyAllCallbacks(userId, packageName, INSTALL_EVENT_TYPE_INSTALL);
@@ -364,7 +367,11 @@
// ADB sets installerPackageName to null, this creates a loophole to bypass BIC which will be
// addressed with b/265203007
private boolean installedByAdb(String initiatingPackageName) {
- return PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName);
+ if(PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName)) {
+ Slog.d(TAG, "handlePackageAdd: is installed by ADB, skipping");
+ return true;
+ }
+ return false;
}
private boolean wasForegroundInstallation(
@@ -407,6 +414,7 @@
if (mBackgroundInstalledPackages.contains(userId, packageName)) {
mCallbackHelper.notifyAllCallbacks(userId, packageName, INSTALL_EVENT_TYPE_UNINSTALL);
}
+ Slog.d(TAG, "handlePackageRemove: removing " + packageName + " from " + userId);
mBackgroundInstalledPackages.remove(userId, packageName);
writeBackgroundInstalledPackagesToDisk();
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3805c02..221b848 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -205,6 +205,7 @@
import com.android.server.os.DeviceIdentifiersPolicyService;
import com.android.server.os.NativeTombstoneManagerService;
import com.android.server.os.SchedulingPolicyService;
+import com.android.server.os.instrumentation.DynamicInstrumentationManagerService;
import com.android.server.pdb.PersistentDataBlockService;
import com.android.server.people.PeopleService;
import com.android.server.permission.access.AccessCheckingService;
@@ -2890,6 +2891,13 @@
mSystemServiceManager.startService(TracingServiceProxy.class);
t.traceEnd();
+ // UprobeStats DynamicInstrumentationManager
+ if (com.android.art.flags.Flags.executableMethodFileOffsets()) {
+ t.traceBegin("StartDynamicInstrumentationManager");
+ mSystemServiceManager.startService(DynamicInstrumentationManagerService.class);
+ t.traceEnd();
+ }
+
// It is now time to start up the app processes...
t.traceBegin("MakeLockSettingsServiceReady");
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp b/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp
new file mode 100644
index 0000000..2c2e5fd
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/Android.bp
@@ -0,0 +1,44 @@
+// 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 {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+ default_team: "trendy_team_system_performance",
+}
+
+android_test {
+ name: "DynamicInstrumentationManagerServiceTests",
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.runner",
+ "hamcrest-library",
+ "platform-test-annotations",
+ "services.core",
+ "testables",
+ "truth",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: [
+ "device-tests",
+ ],
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/AndroidManifest.xml b/services/tests/DynamicInstrumentationManagerServiceTests/AndroidManifest.xml
new file mode 100644
index 0000000..4913d70
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.os.instrumentation" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.os.instrumentation"
+ android:label="DynamicInstrumentationmanagerService Unit Tests"/>
+</manifest>
\ No newline at end of file
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/TEST_MAPPING b/services/tests/DynamicInstrumentationManagerServiceTests/TEST_MAPPING
new file mode 100644
index 0000000..33defed
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "DynamicInstrumentationManagerServiceTests"
+ }
+ ]
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClass.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClass.java
new file mode 100644
index 0000000..04073fa
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClass.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+public abstract class TestAbstractClass {
+ abstract void abstractMethod();
+
+ void concreteMethod() {
+ }
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClassImpl.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClassImpl.java
new file mode 100644
index 0000000..2c25e7a5
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestAbstractClassImpl.java
@@ -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.server;
+
+public class TestAbstractClassImpl extends TestAbstractClass {
+ @Override
+ void abstractMethod() {
+ }
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java
new file mode 100644
index 0000000..085f595
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestClass.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+public class TestClass {
+ void primitiveParams(boolean a, boolean[] b, byte c, byte[] d, char e, char[] f, short g,
+ short[] h, int i, int[] j, long k, long[] l, float m, float[] n, double o, double[] p) {
+ }
+
+ void classParams(String a, String[] b) {
+ }
+
+ private void privateMethod() {
+ }
+
+ /**
+ * docs!
+ */
+ public void publicMethod() {
+ }
+
+ private static class InnerClass {
+ private void innerMethod(InnerClass arg, InnerClass[] argArray) {
+ }
+ }
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterface.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterface.java
new file mode 100644
index 0000000..7af4f25
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterface.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+/**
+ * docs!
+ */
+public interface TestInterface {
+ /**
+ * docs!
+ */
+ void interfaceMethod();
+
+ /**
+ * docs!
+ */
+ default void defaultMethod() {
+ }
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterfaceImpl.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterfaceImpl.java
new file mode 100644
index 0000000..53aecbc
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/TestInterfaceImpl.java
@@ -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.server;
+
+public class TestInterfaceImpl implements TestInterface {
+ @Override
+ public void interfaceMethod() {
+ }
+}
diff --git a/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java
new file mode 100644
index 0000000..5492ba6
--- /dev/null
+++ b/services/tests/DynamicInstrumentationManagerServiceTests/src/com/android/server/os/instrumentation/ParseMethodDescriptorTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os.instrumentation;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+
+import android.os.instrumentation.MethodDescriptor;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.TestAbstractClass;
+import com.android.server.TestAbstractClassImpl;
+import com.android.server.TestClass;
+import com.android.server.TestInterface;
+import com.android.server.TestInterfaceImpl;
+
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+
+
+/**
+ * Test class for
+ * {@link DynamicInstrumentationManagerService#parseMethodDescriptor(ClassLoader,
+ * MethodDescriptor)}.
+ * <p>
+ * Build/Install/Run:
+ * atest FrameworksMockingServicesTests:ParseMethodDescriptorTest
+ */
+@Presubmit
+@SmallTest
+public class ParseMethodDescriptorTest {
+ private static final String[] PRIMITIVE_PARAMS = new String[]{
+ "boolean", "boolean[]", "byte", "byte[]", "char", "char[]", "short", "short[]", "int",
+ "int[]", "long", "long[]", "float", "float[]", "double", "double[]"};
+ private static final String[] CLASS_PARAMS =
+ new String[]{"java.lang.String", "java.lang.String[]"};
+
+ @Test
+ public void primitiveParams() {
+ assertNotNull(parseMethodDescriptor(TestClass.class.getName(), "primitiveParams",
+ PRIMITIVE_PARAMS));
+ }
+
+ @Test
+ public void classParams() {
+ assertNotNull(
+ parseMethodDescriptor(TestClass.class.getName(), "classParams", CLASS_PARAMS));
+ }
+
+ @Test
+ public void publicMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestClass.class.getName(), "publicMethod"));
+ }
+
+ @Test
+ public void privateMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestClass.class.getName(), "privateMethod"));
+ }
+
+ @Test
+ public void innerClass() {
+ assertNotNull(
+ parseMethodDescriptor(TestClass.class.getName() + "$InnerClass", "innerMethod",
+ new String[]{TestClass.class.getName() + "$InnerClass",
+ TestClass.class.getName() + "$InnerClass[]"}));
+ }
+
+ @Test
+ public void interface_concreteMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestInterfaceImpl.class.getName(), "interfaceMethod"));
+ }
+
+ @Test
+ public void interface_defaultMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestInterface.class.getName(), "defaultMethod"));
+ }
+
+ @Test
+ public void abstractClassImpl_abstractMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestAbstractClassImpl.class.getName(), "abstractMethod"));
+ }
+
+ @Test
+ public void abstractClass_concreteMethod() {
+ assertNotNull(
+ parseMethodDescriptor(TestAbstractClass.class.getName(), "concreteMethod"));
+ }
+
+ @Test
+ public void notFound_illegalArgumentException() {
+ assertThrows(IllegalArgumentException.class, () -> parseMethodDescriptor("foo", "bar"));
+ assertThrows(IllegalArgumentException.class,
+ () -> parseMethodDescriptor(TestClass.class.getName(), "bar"));
+ assertThrows(IllegalArgumentException.class,
+ () -> parseMethodDescriptor(TestClass.class.getName(), "primitiveParams",
+ new String[]{"int"}));
+ }
+
+ private Method parseMethodDescriptor(String fqcn, String methodName) {
+ return DynamicInstrumentationManagerService.parseMethodDescriptor(
+ getClass().getClassLoader(),
+ getMethodDescriptor(fqcn, methodName, new String[]{}));
+ }
+
+ private Method parseMethodDescriptor(String fqcn, String methodName, String[] fqParameters) {
+ return DynamicInstrumentationManagerService.parseMethodDescriptor(
+ getClass().getClassLoader(),
+ getMethodDescriptor(fqcn, methodName, fqParameters));
+ }
+
+ private MethodDescriptor getMethodDescriptor(String fqcn, String methodName,
+ String[] fqParameters) {
+ MethodDescriptor methodDescriptor = new MethodDescriptor();
+ methodDescriptor.fullyQualifiedClassName = fqcn;
+ methodDescriptor.methodName = methodName;
+ methodDescriptor.fullyQualifiedParameters = fqParameters;
+ return methodDescriptor;
+ }
+
+
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2a06c3d..6490cbe 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2183,8 +2183,8 @@
* Maximum size in bytes of the PDU to send or download when connected to a non-terrestrial
* network. MmsService will return a result code of MMS_ERROR_TOO_LARGE_FOR_TRANSPORT if
* the PDU exceeds this limit when connected to a non-terrestrial network.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT =
"mms_max_ntn_payload_size_bytes_int";
@@ -9850,9 +9850,8 @@
* manually scanning available cellular network.
* If key is {@code true}, satellite plmn should not be exposed to user and should be
* automatically set, {@code false} otherwise. Default value is {@code true}.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL =
"remove_satellite_plmn_in_manual_network_scan_bool";
@@ -9877,18 +9876,18 @@
/**
* Doesn't support unrestricted traffic on satellite network.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED = 0;
/**
* Support unrestricted but bandwidth_constrained traffic on satellite network.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED = 1;
/**
* Support unrestricted satellite network that serves all traffic.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_DATA_SUPPORT_ALL = 2;
/**
* Indicates what kind of traffic an {@link NetworkCapabilities#NET_CAPABILITY_NOT_RESTRICTED}
@@ -9898,8 +9897,8 @@
* {@link ApnSetting#INFRASTRUCTURE_SATELLITE} from APN infrastructure_bitmask, and this
* configuration is ignored.
* By default it only supports restricted data.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT =
"satellite_data_support_mode_int";
@@ -9911,8 +9910,8 @@
* {@link com.android.ims.ImsConfig.WfcModeFeatureValueConstants#WIFI_PREFERRED}
* {@code false} - roaming preference can be changed by user independently and is not
* overridden when device is connected to non-terrestrial network.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL =
"override_wfc_roaming_mode_while_using_ntn_bool";
@@ -9945,8 +9944,8 @@
* Reference: GSMA TS.43-v11, 2.8.5 Fast Authentication and Token Management.
* `app_name` is an optional attribute in the request and may vary depending on the carrier
* requirement.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING =
"satellite_entitlement_app_name_string";
@@ -9954,9 +9953,8 @@
* URL to redirect user to get more information about the carrier support for satellite.
*
* The default value is empty string.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING =
"satellite_information_redirect_url_string";
/**
@@ -9966,9 +9964,8 @@
* This will need agreement with carriers before enabling this flag.
*
* The default value is false.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL =
"emergency_messaging_supported_bool";
@@ -9983,9 +9980,8 @@
* prompt user to switch to using satellite emergency messaging.
*
* The default value is 30 seconds.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT =
"emergency_call_to_satellite_t911_handover_timeout_millis_int";
@@ -9998,9 +9994,8 @@
* The default capabilities are
* {@link NetworkRegistrationInfo#SERVICE_TYPE_SMS}, and
* {@link NetworkRegistrationInfo#SERVICE_TYPE_MMS}
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY =
"carrier_roaming_satellite_default_services_int_array";
@@ -10031,9 +10026,8 @@
* Defines the NIDD (Non-IP Data Delivery) APN to be used for carrier roaming to satellite
* attachment. For more on NIDD, see 3GPP TS 29.542.
* Note this config is the only source of truth regarding the definition of the APN.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_SATELLITE_NIDD_APN_NAME_STRING =
"satellite_nidd_apn_name_string";
@@ -10044,9 +10038,8 @@
*
* If {@code false}, the emergency call is always blocked if device is in emergency satellite
* mode. Note if device is NOT in emergency satellite mode, emergency call is always allowed.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL =
"satellite_roaming_turn_off_session_for_emergency_call_bool";
@@ -10059,14 +10052,14 @@
/**
* Device can connect to carrier roaming non-terrestrial network automatically.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC = 0;
/**
* Device can connect to carrier roaming non-terrestrial network only if user manually triggers
* satellite connection.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int CARRIER_ROAMING_NTN_CONNECT_MANUAL = 1;
/**
* Indicates carrier roaming non-terrestrial network connect type that the device can use to
@@ -10074,8 +10067,8 @@
* If this key is set to CARRIER_ROAMING_NTN_CONNECT_MANUAL then connect button will be
* displayed to user when the device is eligible to use carrier roaming
* non-terrestrial network.
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT =
"carrier_roaming_ntn_connect_type_int";
@@ -10088,7 +10081,6 @@
* will be made to T911.
*
* The default value is {@link SatelliteManager#EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911}.
- *
*/
@FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
public static final String
@@ -10105,9 +10097,8 @@
* After the timer is expired, device is marked as eligible for satellite communication.
*
* The default value is 180 seconds.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final String KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT =
"carrier_supported_satellite_notification_hysteresis_sec_int";
@@ -10153,7 +10144,9 @@
"satellite_roaming_esos_inactivity_timeout_sec_int";
/**
- * A string array containing the list of messaging package names that support satellite.
+ * A string array containing the list of messaging apps that support satellite.
+ *
+ * The default value contains only "com.google.android.apps.messaging"
*
* @hide
*/
@@ -10166,9 +10159,8 @@
* the default APN (i.e. internet) will be used for tethering.
*
* This config is only available when using Preset APN(not user edited) as Preferred APN.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_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";
@@ -11313,6 +11305,8 @@
NetworkRegistrationInfo.SERVICE_TYPE_SMS,
NetworkRegistrationInfo.SERVICE_TYPE_MMS
});
+ sDefaults.putStringArray(KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY, new String[]{
+ "com.google.android.apps.messaging"});
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, false);
sDefaults.putInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 7be3f33..88dddcf 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -483,43 +483,43 @@
/**
* Telephony framework needs to access the current location of the device to perform the
* request. However, location in the settings is disabled by users.
- *
* @hide
*/
- @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_LOCATION_DISABLED = 25;
/**
* Telephony framework needs to access the current location of the device to perform the
* request. However, Telephony fails to fetch the current location from location service.
- *
* @hide
*/
- @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_LOCATION_NOT_AVAILABLE = 26;
/**
* Emergency call is in progress.
- *
* @hide
*/
- @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS = 27;
/**
* Disabling satellite is in progress.
- *
* @hide
*/
- @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_DISABLE_IN_PROGRESS = 28;
/**
* Enabling satellite is in progress.
- *
* @hide
*/
- @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29;
/** @hide */
@@ -715,7 +715,7 @@
public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2;
/**
- * This intent will be broadcasted if there are any change to list of subscriber informations.
+ * This intent will be broadcasted if there are any change to list of subscriber information.
* This intent will be sent only to the app with component defined in
* config_satellite_carrier_roaming_esos_provisioned_class and package defined in
* config_satellite_gateway_service_package
@@ -1349,12 +1349,16 @@
* The satellite modem is being powered on.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_MODEM_STATE_ENABLING_SATELLITE = 8;
/**
* The satellite modem is being powered off.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_MODEM_STATE_DISABLING_SATELLITE = 9;
/**
@@ -1414,6 +1418,8 @@
* there is any incoming message.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3;
/**
@@ -1421,6 +1427,8 @@
* is the last message to emergency service provider indicating still needs help.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4;
/**
@@ -1428,12 +1436,16 @@
* is the last message to emergency service provider indicating no more help is needed.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5;
/**
* Datagram type indicating that the message to be sent or received is of type SMS.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int DATAGRAM_TYPE_SMS = 6;
/**
@@ -1441,6 +1453,8 @@
* for pending incoming SMS.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS = 7;
/** @hide */
@@ -1461,6 +1475,8 @@
* Satellite communication restricted by user.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS)
public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0;
/**
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index 1abe77f..f260e27 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -188,7 +188,7 @@
?: throw IllegalArgumentException(
"Invalid feature version input for $name: ${featureArgs[1]}"
)
- FeatureInfo(name, featureArgs[1].toInt(), readonly = true)
+ FeatureInfo(name, featureVersion, readonly = true)
}
}
}