diff options
author | Xin Li <delphij@google.com> | 2024-03-07 06:41:08 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-03-07 06:41:08 +0000 |
commit | 492983e9a0a81933da4c2105e0f95f1c30bd234b (patch) | |
tree | ec923bc9db380a1479ecd146416686eea6f5344d | |
parent | 34573462f4fbad6d673325fc336faa2bfb6c22aa (diff) | |
parent | 1b1530f8333c205ae7c0b4ecc3347cbfcfaf0a21 (diff) | |
download | telephony-492983e9a0a81933da4c2105e0f95f1c30bd234b.tar.gz |
Merge "Merge Android 14 QPR2 to AOSP main" into main
210 files changed, 26894 insertions, 10583 deletions
diff --git a/Android.bp b/Android.bp index 5b684d2362..121236aa4d 100644 --- a/Android.bp +++ b/Android.bp @@ -83,14 +83,14 @@ java_library { "android.hardware.radio-V1.4-java", "android.hardware.radio-V1.5-java", "android.hardware.radio-V1.6-java", - "android.hardware.radio.config-V2-java", - "android.hardware.radio.data-V2-java", - "android.hardware.radio.ims-V1-java", - "android.hardware.radio.messaging-V2-java", - "android.hardware.radio.modem-V2-java", - "android.hardware.radio.network-V2-java", - "android.hardware.radio.sim-V2-java", - "android.hardware.radio.voice-V2-java", + "android.hardware.radio.config-V3-java", + "android.hardware.radio.data-V3-java", + "android.hardware.radio.ims-V2-java", + "android.hardware.radio.messaging-V3-java", + "android.hardware.radio.modem-V3-java", + "android.hardware.radio.network-V3-java", + "android.hardware.radio.sim-V3-java", + "android.hardware.radio.voice-V3-java", "voip-common", "ims-common", "unsupportedappusage", @@ -100,7 +100,6 @@ java_library { "android.hardware.radio.config-V1.1-java-shallow", "android.hardware.radio.config-V1.2-java-shallow", "android.hardware.radio.config-V1.3-java-shallow", - "android.hardware.radio.deprecated-V1.0-java-shallow", "ecc-protos-lite", "libphonenumber-nogeocoder", "PlatformProperties", diff --git a/TEST_MAPPING b/TEST_MAPPING index 55f1ccc319..59685b14af 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -9,7 +9,8 @@ ] }, { - "name": "CarrierAppIntegrationTestCases" + "name": "CarrierAppIntegrationTestCases", + "keywords": ["internal"] }, { "name": "CtsTelephony2TestCases", diff --git a/flags/Android.bp b/flags/Android.bp new file mode 100644 index 0000000000..3c0deeef67 --- /dev/null +++ b/flags/Android.bp @@ -0,0 +1,37 @@ +// +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +aconfig_declarations { + name: "telephony_flags", + package: "com.android.internal.telephony.flags", + srcs: [ + "data.aconfig", + "domainselection.aconfig", + "ims.aconfig", + "messaging.aconfig", + "misc.aconfig", + "network.aconfig", + "subscription.aconfig", + "uicc.aconfig", + "satellite.aconfig", + "iwlan.aconfig", + "telephony.aconfig", + ], +} diff --git a/flags/data.aconfig b/flags/data.aconfig new file mode 100644 index 0000000000..267048e219 --- /dev/null +++ b/flags/data.aconfig @@ -0,0 +1,92 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "auto_switch_allow_roaming" + namespace: "telephony" + description: "Allow using roaming network as target if user allows it from settings." + bug: "306488039" +} + +flag { + name: "auto_data_switch_rat_ss" + namespace: "telephony" + description: "Whether switch for better rat and signal strength" + bug:"260928808" +} + +flag { + name: "use_alarm_callback" + namespace: "telephony" + description: "Use alarm callback instead of broadcast." + bug: "311476875" +} + +flag { + name: "refine_preferred_data_profile_selection" + namespace: "telephony" + description: "Upon internet network connect, refine selection of preferred data profile." + bug: "311476883" +} + +flag { + name: "unthrottle_check_transport" + namespace: "telephony" + description: "Check transport when unthrottle." + bug: "303922311" +} + +flag { + name: "relax_ho_teardown" + namespace: "telephony" + description: "Relax handover tear down if the device is currently in voice call." + bug: "270895912" +} + +flag { + name: "allow_mmtel_in_non_vops" + namespace: "telephony" + description: "Allow bring up MMTEL in nonVops area specified by carrier config." + bug: "241198464" +} + +flag { + name: "metered_embb_urlcc" + namespace: "telephony" + description: "Force networks that have PRIORITIZE_BANDWIDTH or PRIORITIZE_LATENCY to be metered." + bug: "301310451" + } + +flag { + name: "slicing_additional_error_codes" + namespace: "telephony" + description: "Support additional slicing error codes and functionality." + bug: "307378699" +} + +flag { + name: "apn_setting_field_support_flag" + namespace: "telephony" + description: "Expose apn setting supporting field" + bug: "307038091" +} + +flag { + name: "network_validation" + namespace: "telephony" + description: "Request network validation for data networks and response status." + bug:"286171724" +} + +flag { + name: "notify_data_activity_changed_with_slot" + namespace: "telephony" + description: "notify data activity changed for slot id" + bug: "309896936" +} + +flag { + name: "vonr_enabled_metric" + namespace: "telephony" + description: "Collect vonr status in voice call metric" + bug:"288449751" +} diff --git a/flags/domainselection.aconfig b/flags/domainselection.aconfig new file mode 100644 index 0000000000..2e1dfc834d --- /dev/null +++ b/flags/domainselection.aconfig @@ -0,0 +1,29 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "ap_domain_selection_enabled" + namespace: "telephony" + description: "This flag controls AP domain selection feature." + bug:"258112541" +} + +flag { + name: "use_aosp_domain_selection_service" + namespace: "telephony" + description: "This flag controls AOSP's domain selection service supported." + bug:"258112541" +} + +flag { + name: "use_oem_domain_selection_service" + namespace: "telephony" + description: "This flag controls OEMs' domain selection service supported." + bug:"258112541" +} + +flag { + name: "domain_selection_metrics_enabled" + namespace: "telephony" + description: "This flag controls domain selection metrics." + bug:"258112541" +} diff --git a/flags/ims.aconfig b/flags/ims.aconfig new file mode 100644 index 0000000000..4638194f81 --- /dev/null +++ b/flags/ims.aconfig @@ -0,0 +1,43 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "conference_hold_unhold_changed_to_send_message" + namespace: "telephony" + description: "This flag controls Conference’s hold & unHold operation changed to send a message" + bug:"288002989" +} + +flag { + name: "ignore_already_terminated_incoming_call_before_registering_listener" + namespace: "telephony" + description: "This flag ignores the incoming call by throwing an exception if the call was already terminated before the framework registers the listener for the incoming call" + bug:"289461637" +} + +flag { + name: "clear_cached_ims_phone_number_when_device_lost_ims_registration" + namespace: "telephony" + description: "This flag clears cached IMS phone number when device lost IMS registration" + bug:"288002989" +} + +flag { + name: "update_ims_service_by_gathering_provisioning_changes" + namespace: "telephony" + description: "This flag is created to prevent unnecessary updates when multiple provisioning items to update ims service are changed." + bug:"302281114" +} + +flag { + name: "add_rat_related_suggested_action_to_ims_registration" + namespace: "telephony" + description: "This flag is for adding suggested actions related to RAT to ims registration" + bug:"290573256" +} + +flag { + name: "terminate_active_video_call_when_accepting_second_video_call_as_audio_only" + namespace: "telephony" + description: "This flag terminates active video call instead holding when accepting 2nd incoming video call as audio only" + bug:"309548300" +} diff --git a/flags/iwlan.aconfig b/flags/iwlan.aconfig new file mode 100644 index 0000000000..0dc9f8db40 --- /dev/null +++ b/flags/iwlan.aconfig @@ -0,0 +1,14 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "enable_aead_algorithms" + namespace: "telephony" + description: "Add AEAD algorithms AES-GCM-8, AES-GCM-12 and AES-GCM-16 to IWLAN" + bug:"306119890" +} +flag { + name: "enable_multiple_sa_proposals" + namespace: "telephony" + description: "Add multiple proposals of cipher suites in IKE SA and Child SA" + bug:"287296642" +} diff --git a/flags/messaging.aconfig b/flags/messaging.aconfig new file mode 100644 index 0000000000..1ba89baa47 --- /dev/null +++ b/flags/messaging.aconfig @@ -0,0 +1,22 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "reject_bad_sub_id_interaction" + namespace: "telephony" + description: "Previously, the DB allows insertion of a random sub Id, but doesn't allow query it. This change rejects such interaction." + bug: "294125411" +} + +flag { + name: "sms_domain_selection_enabled" + namespace: "telephony" + description: "This flag controls AP domain selection support for normal/emergency SMS." + bug: "262804071" +} + +flag { + name: "mms_disabled_error" + namespace: "telephony" + description: "This flag controls the support of the new MMS error code MMS_ERROR_MMS_DISABLED." + bug: "305062594" +}
\ No newline at end of file diff --git a/flags/misc.aconfig b/flags/misc.aconfig new file mode 100644 index 0000000000..835efeefce --- /dev/null +++ b/flags/misc.aconfig @@ -0,0 +1,72 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "do_not_override_precise_label" + namespace: "telephony" + description: "When set, Telecom will not override the precise label for certain disconnect causes." + bug: "296968778" + is_fixed_read_only: true +} + +flag { + name: "log_mms_sms_database_access_info" + namespace: "telephony" + description: "Whether to log MMS/SMS database access info and report anomaly when getting exception." + bug: "275225402" +} + +flag { + name: "stop_spamming_emergency_notification" + namespace: "telephony" + description: "When set, the no wifi emergency calling availability notif will have a do not ask again button" + bug: "275225402" +} + +flag { + name: "enable_wps_check_api_flag" + namespace: "telephony" + description: "Enable system api isWpsCallNumber. Its an utility api to check if the dialed number is for Wireless Priority Service call." + bug: "304272356" +} + +flag { + name: "ensure_access_to_call_settings_is_restricted" + namespace: "telephony" + description: "Check if access to mobile network configs restricted before displaying call options" + bug: "309655251" +} + +flag { + name: "reorganize_roaming_notification" + namespace: "telephony" + description: "Reorganize conditions to show and dismiss roaming notifications." + bug: "310594087" +} + +flag { + name: "dismiss_network_selection_notification_on_sim_disable" + namespace: "telephony" + description: "Fix to dismiss network selection notification when disable sim." + bug: "310594186" +} + +flag { + name: "enable_telephony_analytics" + namespace: "telephony" + description: "Enable Telephony Analytics information of Service State , Sms and Call scenarios" + bug: "309896524" +} + +flag { + name: "show_call_id_and_call_waiting_in_additional_settings_menu" + namespace: "telephony" + description: "Expose carrier config KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL and KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL." + bug: "310264981" +} + +flag { + name: "radio_info_is_radio_on" + namespace: "telephony" + description: "change method to show mobile radio power from service state to radio power" + bug: "306084899" +} diff --git a/flags/network.aconfig b/flags/network.aconfig new file mode 100644 index 0000000000..27489f40f5 --- /dev/null +++ b/flags/network.aconfig @@ -0,0 +1,22 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "enable_carrier_config_n1_control" + namespace: "telephony" + description: "enabling this flag allows KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY to control N1 mode enablement" + bug:"302033535" +} + +flag { + name: "hide_roaming_icon" + namespace: "telephony" + description: "Allow carriers to hide the roaming (R) icon when roaming." + bug: "301467052" +} + +flag { + name: "enable_identifier_disclosure_transparency" + namespace: "telephony" + description: "Allows the framework to register for CellularIdentifierDisclosure events and emit notifications to the user about them" + bug: "276752426" +} diff --git a/flags/satellite.aconfig b/flags/satellite.aconfig new file mode 100644 index 0000000000..e640e6ea2e --- /dev/null +++ b/flags/satellite.aconfig @@ -0,0 +1,15 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "oem_enabled_satellite_flag" + namespace: "telephony" + description: "This flag controls satellite communication supported by OEMs." + bug:"291811962" +} + +flag { + name: "carrier_enabled_satellite_flag" + namespace: "telephony" + description: "This flag controls satellite communication supported by carriers." + bug:"296437388" +}
\ No newline at end of file diff --git a/flags/subscription.aconfig b/flags/subscription.aconfig new file mode 100644 index 0000000000..0521cb998b --- /dev/null +++ b/flags/subscription.aconfig @@ -0,0 +1,8 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "work_profile_api_split" + namespace: "telephony" + description: "To support separation between personal and work from TelephonyManager and SubscriptionManager API perspective." + bug: "296076674" +}
\ No newline at end of file diff --git a/flags/telephony.aconfig b/flags/telephony.aconfig new file mode 100644 index 0000000000..b849d53e64 --- /dev/null +++ b/flags/telephony.aconfig @@ -0,0 +1,15 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "enforce_telephony_feature_mapping" + namespace: "telephony" + description: "This flag controls telephony feature flags mapping." + bug:"297989574" +} + +flag { + name: "enforce_telephony_feature_mapping_for_public_apis" + namespace: "telephony" + description: "This flag controls telephony feature flags mapping for public APIs and CTS." + bug:"297989574" +} diff --git a/flags/uicc.aconfig b/flags/uicc.aconfig new file mode 100644 index 0000000000..b2024b006e --- /dev/null +++ b/flags/uicc.aconfig @@ -0,0 +1,20 @@ +package: "com.android.internal.telephony.flags" + +flag { + name: "esim_bootstrap_provisioning_flag" + namespace: "telephony" + description: "This flag controls eSIM Bootstrap provisioning feature support." + bug:"298567545" +} +flag { + name: "imsi_key_retry_download_on_phone_unlock" + namespace: "telephony" + description: "This flag controls to download the IMSI encryption keys after user unlocks the phone." + bug:"303780982" +} +flag { + name: "carrier_restriction_status" + namespace: "telephony" + description: "This flag control the visibility of the getCarrierRestrictionStatus in carrierRestrictionRules class." + bug:"313553044" +}
\ No newline at end of file diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index 2e569f042c..d7a60622df 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -190,6 +190,12 @@ message PersistAtoms { /* Number of time the user toggled the data switch feature since the last collection. */ optional int32 auto_data_switch_toggle_count = 55; + /* Consolidated emergency numbers list information. */ + repeated EmergencyNumbersInfo emergency_numbers_info = 56; + + /* Timestamp of last emergency number pull. */ + optional int64 emergency_number_pull_timestamp_millis = 57; + /** Snapshot of satellite controller. */ repeated SatelliteController satellite_controller = 58; @@ -225,12 +231,6 @@ message PersistAtoms { /* Timestamp of last satellite_sos_message_recommender pull. */ optional int64 satellite_sos_message_recommender_pull_timestamp_millis = 69; - - /* Consolidated emergency numbers list information. */ - repeated EmergencyNumbersInfo emergency_numbers_info = 56; - - /* Timestamp of last emergency number pull. */ - optional int64 emergency_number_pull_timestamp_millis = 57; } // The canonical versions of the following enums live in: @@ -277,6 +277,10 @@ message VoiceCallSession { optional int32 fold_state = 34; optional int64 rat_switch_count_after_connected = 35; optional bool handover_in_progress = 36; + optional bool is_iwlan_cross_sim_at_start = 37; + optional bool is_iwlan_cross_sim_at_end = 38; + optional bool is_iwlan_cross_sim_at_connected = 39; + optional bool vonr_enabled = 40; // Internal use only optional int64 setup_begin_millis = 10001; @@ -365,6 +369,7 @@ message DataCallSession { repeated int32 handover_failure_causes = 20; repeated int32 handover_failure_rat = 21; optional bool is_non_dds = 22; + optional bool is_iwlan_cross_sim = 23; } message CellularServiceState { @@ -382,6 +387,7 @@ message CellularServiceState { optional int32 fold_state = 12; optional bool override_voice_service = 13; optional bool isDataEnabled = 14; + optional bool is_iwlan_cross_sim = 15; // Internal use only optional int64 last_used_millis = 10001; @@ -408,6 +414,7 @@ message ImsRegistrationTermination { optional int32 extra_code = 6; optional string extra_message = 7; optional int32 count = 8; + optional bool is_iwlan_cross_sim = 9; // Internal use only optional int64 last_used_millis = 10001; @@ -427,6 +434,9 @@ message ImsRegistrationStats { optional int64 video_available_millis = 10; optional int64 ut_capable_millis = 11; optional int64 ut_available_millis = 12; + optional int64 registering_millis = 13; + optional int64 unregistered_millis = 14; + optional bool is_iwlan_cross_sim = 15; // Internal use only optional int64 last_used_millis = 10001; @@ -588,6 +598,41 @@ message OutgoingShortCodeSms { optional int32 short_code_sms_count = 3; } +message EmergencyNumbersInfo { + enum ServiceCategory { + EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = 0; + EMERGENCY_SERVICE_CATEGORY_POLICE = 1; + EMERGENCY_SERVICE_CATEGORY_AMBULANCE = 2; + EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = 3; + EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = 4; + EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = 5; + EMERGENCY_SERVICE_CATEGORY_MIEC = 6; + EMERGENCY_SERVICE_CATEGORY_AIEC = 7; + } + enum Source { + EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 0; + EMERGENCY_NUMBER_SOURCE_SIM = 1; + EMERGENCY_NUMBER_SOURCE_DATABASE = 2; + EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 3; + EMERGENCY_NUMBER_SOURCE_DEFAULT = 4; + } + enum CallRoute { + EMERGENCY_CALL_ROUTE_UNKNOWN = 0; + EMERGENCY_CALL_ROUTE_EMERGENCY = 1; + EMERGENCY_CALL_ROUTE_NORMAL = 2; + } + optional bool is_db_version_ignored = 1; + optional int32 asset_version = 2; + optional int32 ota_version = 3; + optional string number = 4; + optional string country_iso = 5; + optional string mnc = 6; + optional CallRoute route = 7; + repeated string urns = 8; + repeated ServiceCategory service_categories = 9; + repeated Source sources = 10; +} + message SatelliteController { optional int32 count_of_satellite_service_enablements_success = 1; optional int32 count_of_satellite_service_enablements_fail = 2; @@ -640,39 +685,7 @@ message SatelliteSosMessageRecommender { optional bool is_ims_registered = 3; optional int32 cellular_service_state = 4; optional int32 count = 5; -} - -message EmergencyNumbersInfo { - enum ServiceCategory { - EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = 0; - EMERGENCY_SERVICE_CATEGORY_POLICE = 1; - EMERGENCY_SERVICE_CATEGORY_AMBULANCE = 2; - EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = 3; - EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = 4; - EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = 5; - EMERGENCY_SERVICE_CATEGORY_MIEC = 6; - EMERGENCY_SERVICE_CATEGORY_AIEC = 7; - } - enum Source { - EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 0; - EMERGENCY_NUMBER_SOURCE_SIM = 1; - EMERGENCY_NUMBER_SOURCE_DATABASE = 2; - EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 3; - EMERGENCY_NUMBER_SOURCE_DEFAULT = 4; - } - enum CallRoute { - EMERGENCY_CALL_ROUTE_UNKNOWN = 0; - EMERGENCY_CALL_ROUTE_EMERGENCY = 1; - EMERGENCY_CALL_ROUTE_NORMAL = 2; - } - optional bool is_db_version_ignored = 1; - optional int32 asset_version = 2; - optional int32 ota_version = 3; - optional string number = 4; - optional string country_iso = 5; - optional string mnc = 6; - optional CallRoute route = 7; - repeated string urns = 8; - repeated ServiceCategory service_categories = 9; - repeated Source sources = 10; + optional bool is_multi_sim = 6; + optional int32 recommending_handover_type = 7; + optional bool is_satellite_allowed_in_current_location = 8; } diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index b8de97522e..b33b732fbd 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -18,7 +18,6 @@ package com.android.internal.telephony; import android.annotation.NonNull; -import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.AsyncResult; @@ -69,8 +68,6 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList(); protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList(); @UnsupportedAppUsage - protected Registrant mUnsolOemHookRawRegistrant; - @UnsupportedAppUsage protected RegistrantList mOtaProvisionRegistrants = new RegistrantList(); @UnsupportedAppUsage protected RegistrantList mCallWaitingInfoRegistrants = new RegistrantList(); @@ -121,13 +118,8 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList(); protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList(); - protected RegistrantList mPendingSatelliteMessageCountRegistrants = new RegistrantList(); - protected RegistrantList mNewSatelliteMessagesRegistrants = new RegistrantList(); - protected RegistrantList mSatelliteMessagesTransferCompleteRegistrants = new RegistrantList(); - protected RegistrantList mSatellitePointingInfoChangedRegistrants = new RegistrantList(); - protected RegistrantList mSatelliteModeChangedRegistrants = new RegistrantList(); - protected RegistrantList mSatelliteRadioTechnologyChangedRegistrants = new RegistrantList(); - protected RegistrantList mSatelliteProvisionStateChangedRegistrants = new RegistrantList(); + protected RegistrantList mImeiInfoRegistrants = new RegistrantList(); + protected RegistrantList mCellularIdentifierDisclosedRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -681,17 +673,6 @@ public abstract class BaseCommands implements CommandsInterface { mSignalInfoRegistrants.addUnique(h, what, obj); } - public void setOnUnsolOemHookRaw(Handler h, int what, Object obj) { - mUnsolOemHookRawRegistrant = new Registrant (h, what, obj); - } - - public void unSetOnUnsolOemHookRaw(Handler h) { - if (mUnsolOemHookRawRegistrant != null && mUnsolOemHookRawRegistrant.getHandler() == h) { - mUnsolOemHookRawRegistrant.clear(); - mUnsolOemHookRawRegistrant = null; - } - } - @Override public void unregisterForSignalInfo(Handler h) { mSignalInfoRegistrants.remove(h); @@ -1011,18 +992,6 @@ public abstract class BaseCommands implements CommandsInterface { } @Override - public void startLceService(int reportIntervalMs, boolean pullMode, Message result) { - } - - @Override - public void stopLceService(Message result) { - } - - @Override - public void pullLceData(Message result) { - } - - @Override public void registerForLceInfo(Handler h, int what, Object obj) { synchronized (mStateMonitor) { mLceInfoRegistrants.addUnique(h, what, obj); @@ -1208,80 +1177,21 @@ public abstract class BaseCommands implements CommandsInterface { mTriggerImsDeregistrationRegistrants.remove(h); } + /** + * Register to listen for the changes in the primary IMEI with respect to the sim slot. + */ @Override - public void registerForPendingSatelliteMessageCount( - @NonNull Handler h, int what, @Nullable Object obj) { - mPendingSatelliteMessageCountRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) { - mPendingSatelliteMessageCountRegistrants.remove(h); - } - - @Override - public void registerForNewSatelliteMessages( - @NonNull Handler h, int what, @Nullable Object obj) { - mNewSatelliteMessagesRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForNewSatelliteMessages(@NonNull Handler h) { - mNewSatelliteMessagesRegistrants.remove(h); - } - - @Override - public void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, - int what, @Nullable Object obj) { - mSatelliteMessagesTransferCompleteRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) { - mSatelliteMessagesTransferCompleteRegistrants.remove(h); - } - - @Override - public void registerForSatellitePointingInfoChanged(@NonNull Handler h, - int what, @Nullable Object obj) { - mSatellitePointingInfoChangedRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) { - mSatellitePointingInfoChangedRegistrants.remove(h); - } - - @Override - public void registerForSatelliteModeChanged(@NonNull Handler h, - int what, @Nullable Object obj) { - mSatelliteModeChangedRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForSatelliteModeChanged(@NonNull Handler h) { - mSatelliteModeChangedRegistrants.remove(h); - } - - @Override - public void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h, - int what, @Nullable Object obj) { - mSatelliteRadioTechnologyChangedRegistrants.add(h, what, obj); - } - - @Override - public void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) { - mSatelliteRadioTechnologyChangedRegistrants.remove(h); + public void registerForImeiMappingChanged(Handler h, int what, Object obj) { + mImeiInfoRegistrants.add(h, what, obj); } @Override - public void registerForSatelliteProvisionStateChanged(@NonNull Handler h, - int what, @Nullable Object obj) { - mSatelliteProvisionStateChangedRegistrants.add(h, what, obj); + public void registerForCellularIdentifierDisclosures(Handler h, int what, Object obj) { + mCellularIdentifierDisclosedRegistrants.add(h, what, obj); } @Override - public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) { - mSatelliteProvisionStateChangedRegistrants.remove(h); + public void unregisterForCellularIdentifierDisclosures(Handler h) { + mCellularIdentifierDisclosedRegistrants.remove(h); } } diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java index 195ef16165..9143f21105 100644 --- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java +++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java @@ -20,6 +20,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import android.app.AlarmManager; import android.app.DownloadManager; +import android.app.KeyguardManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -40,6 +41,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.flags.FeatureFlags; import org.json.JSONArray; import org.json.JSONException; @@ -108,6 +110,7 @@ public class CarrierKeyDownloadManager extends Handler { private String mURL; private boolean mAllowedOverMeteredNetwork = false; private boolean mDeleteOldKeyAfterDownload = false; + private boolean mIsRequiredToHandleUnlock; private TelephonyManager mTelephonyManager; private UserManager mUserManager; @@ -116,13 +119,16 @@ public class CarrierKeyDownloadManager extends Handler { public int mCarrierId; @VisibleForTesting public long mDownloadId; + private final FeatureFlags mFeatureFlags; - public CarrierKeyDownloadManager(Phone phone) { + public CarrierKeyDownloadManager(Phone phone, FeatureFlags featureFlags) { mPhone = phone; + mFeatureFlags = featureFlags; mContext = phone.getContext(); IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_KEY_RENEWAL_ALARM_PREFIX); filter.addAction(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD); + filter.addAction(Intent.ACTION_USER_PRESENT); mContext.registerReceiver(mBroadcastReceiver, filter, null, phone); mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); mTelephonyManager = mContext.getSystemService(TelephonyManager.class) @@ -186,6 +192,16 @@ public class CarrierKeyDownloadManager extends Handler { Log.d(LOG_TAG, "Handling reset intent: " + action); sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE); } + } else if (action.equals(Intent.ACTION_USER_PRESENT)) { + // The Carrier key download fails when SIM is inserted while device is locked + // hence adding a retry logic when device is unlocked. + Log.d(LOG_TAG, + "device unlocked, isRequiredToHandleUnlock = " + mIsRequiredToHandleUnlock + + ", slotIndex = " + slotIndex); + if (mIsRequiredToHandleUnlock) { + mIsRequiredToHandleUnlock = false; + sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE); + } } } }; @@ -224,6 +240,16 @@ public class CarrierKeyDownloadManager extends Handler { // keys, we'll still want to renew the alarms, and try downloading the key a day // later. if (!downloadStartedSuccessfully) { + // If download fails due to the device lock, we will reattempt once the device + // is unlocked. + if (mFeatureFlags.imsiKeyRetryDownloadOnPhoneUnlock()) { + KeyguardManager keyguardManager = mContext.getSystemService( + KeyguardManager.class); + if (keyguardManager.isKeyguardSecure()) { + Log.e(LOG_TAG, "Key download failed in device lock state"); + mIsRequiredToHandleUnlock = true; + } + } resetRenewalAlarm(); } } else { @@ -233,6 +259,7 @@ public class CarrierKeyDownloadManager extends Handler { // delete any existing alarms. cleanupRenewalAlarms(); mPhone.deleteCarrierInfoForImsiEncryption(getSimCarrierId()); + } } @@ -622,7 +649,8 @@ public class CarrierKeyDownloadManager extends Handler { mCarrierId = carrierId; mDownloadId = carrierKeyDownloadRequestId; } catch (Exception e) { - Log.e(LOG_TAG, "exception trying to download key from url: " + mURL); + Log.e(LOG_TAG, "exception trying to download key from url: " + mURL + ", Exception = " + + e.getMessage()); return false; } return true; diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index ab7ebc42d7..67be1b6c8b 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -560,7 +560,7 @@ public class CarrierPrivilegesTracker extends Handler { } private void updateCertsForPackage(@NonNull PackageInfo pkg) { - Set<String> certs = new ArraySet<>(); + Set<String> certs = new ArraySet<>(1); List<Signature> signatures = UiccAccessRule.getSignatures(pkg); for (Signature signature : signatures) { byte[] sha1 = UiccAccessRule.getCertHash(signature, SHA_1); @@ -773,7 +773,7 @@ public class CarrierPrivilegesTracker extends Handler { return mCachedUids.get(pkgName); } - Set<Integer> uids = new ArraySet<>(); + Set<Integer> uids = new ArraySet<>(1); List<UserInfo> users = mUserManager.getUsers(); for (UserInfo user : users) { int userId = user.getUserHandle().getIdentifier(); diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java index 93f5ab01e7..6b99b56a5d 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -16,16 +16,22 @@ package com.android.internal.telephony; +import android.annotation.NonNull; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.PersistableBundle; +import android.preference.PreferenceManager; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.RadioAccessFamily; @@ -37,6 +43,7 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.NetworkTypeBitMask; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.telephony.util.NotificationChannelController; import com.android.telephony.Rlog; @@ -66,6 +73,11 @@ public class CarrierServiceStateTracker extends Handler { public static final int NOTIFICATION_PREF_NETWORK = 1000; public static final int NOTIFICATION_EMERGENCY_NETWORK = 1001; + + @VisibleForTesting + public static final String ACTION_NEVER_ASK_AGAIN = "SilenceNoWifiEmrgCallingNotification"; + public final NotificationActionReceiver mActionReceiver = new NotificationActionReceiver(); + @VisibleForTesting public static final String EMERGENCY_NOTIFICATION_TAG = "EmergencyNetworkNotification"; @@ -75,6 +87,7 @@ public class CarrierServiceStateTracker extends Handler { private long mAllowedNetworkType = -1; private AllowedNetworkTypesListener mAllowedNetworkTypesListener; private TelephonyManager mTelephonyManager; + @NonNull private final FeatureFlags mFeatureFlags; /** * The listener for allowed network types changed @@ -95,7 +108,9 @@ public class CarrierServiceStateTracker extends Handler { } } - public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) { + public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst, + @NonNull FeatureFlags featureFlags) { + mFeatureFlags = featureFlags; this.mPhone = phone; this.mSST = sst; mTelephonyManager = mPhone.getContext().getSystemService( @@ -144,12 +159,24 @@ public class CarrierServiceStateTracker extends Handler { } }); - registerNotificationTypes(); + if (!mPhone.getContext().getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH)) { + registerNotificationTypes(); + } + mAllowedNetworkType = RadioAccessFamily.getNetworkTypeFromRaf( (int) mPhone.getAllowedNetworkTypes( TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER)); mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(); registerAllowedNetworkTypesListener(); + + if (mFeatureFlags.stopSpammingEmergencyNotification()) { + // register a receiver for notification actions + mPhone.getContext().registerReceiver( + mActionReceiver, + new IntentFilter(ACTION_NEVER_ASK_AGAIN), + Context.RECEIVER_NOT_EXPORTED); + } } /** @@ -376,11 +403,18 @@ public class CarrierServiceStateTracker extends Handler { */ @VisibleForTesting public void sendNotification(NotificationType notificationType) { + Context context = mPhone.getContext(); + if (!evaluateSendingMessage(notificationType)) { return; } - Context context = mPhone.getContext(); + if (mFeatureFlags.stopSpammingEmergencyNotification() + && shouldSilenceEmrgNetNotif(notificationType, context)) { + Rlog.i(LOG_TAG, "sendNotification: silencing NOTIFICATION_EMERGENCY_NETWORK"); + return; + } + Notification.Builder builder = getNotificationBuilder(notificationType); // set some common attributes builder.setWhen(System.currentTimeMillis()) @@ -394,6 +428,15 @@ public class CarrierServiceStateTracker extends Handler { } /** + * This helper checks if the user has set a flag to silence the notification permanently + */ + private boolean shouldSilenceEmrgNetNotif(NotificationType notificationType, Context context) { + return notificationType.getTypeId() == NOTIFICATION_EMERGENCY_NETWORK + && PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(ACTION_NEVER_ASK_AGAIN, false); + } + + /** * Cancel notifications if a registration is pending or has been sent. **/ public void cancelNotification(NotificationType notificationType) { @@ -646,12 +689,57 @@ public class CarrierServiceStateTracker extends Handler { com.android.internal.R.string.EmergencyCallWarningTitle); CharSequence details = res.getText( com.android.internal.R.string.EmergencyCallWarningSummary); - return new Notification.Builder(context) - .setContentTitle(title) - .setStyle(new Notification.BigTextStyle().bigText(details)) - .setContentText(details) - .setOngoing(true) - .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); + if (mFeatureFlags.stopSpammingEmergencyNotification()) { + return new Notification.Builder(context) + .setContentTitle(title) + .setStyle(new Notification.BigTextStyle().bigText(details)) + .setContentText(details) + .setOngoing(true) + .setActions(createDoNotShowAgainAction(context)) + .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); + } else { + return new Notification.Builder(context) + .setContentTitle(title) + .setStyle(new Notification.BigTextStyle().bigText(details)) + .setContentText(details) + .setOngoing(true) + .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); + } + } + + /** + * add a button to the notification that has a broadcast intent embedded to silence the + * notification + */ + private Notification.Action createDoNotShowAgainAction(Context context) { + final PendingIntent pendingIntent = PendingIntent.getBroadcast( + context, + 0, + new Intent(ACTION_NEVER_ASK_AGAIN), + PendingIntent.FLAG_IMMUTABLE); + return new Notification.Action.Builder(null, "Do Not Show Again", + pendingIntent).build(); + } + } + + /** + * This receiver listens to notification actions and can be utilized to do things like silence + * a notification that is spammy. + */ + public class NotificationActionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_NEVER_ASK_AGAIN)) { + Rlog.i(LOG_TAG, "NotificationActionReceiver: ACTION_NEVER_ASK_AGAIN"); + // insert a key to silence future notifications + SharedPreferences.Editor editor = + PreferenceManager.getDefaultSharedPreferences(context).edit(); + editor.putBoolean(ACTION_NEVER_ASK_AGAIN, true); + editor.apply(); + // Note: If another action is added, unregistering here should be removed. However, + // since there is no longer a reason to broadcasts, cleanup mActionReceiver. + context.unregisterReceiver(mActionReceiver); + } } } } diff --git a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java index 33cde4f267..e187989c50 100644 --- a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java +++ b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java @@ -58,7 +58,7 @@ public class CarrierServicesSmsFilter { public static final int EVENT_ON_FILTER_COMPLETE_NOT_CALLED = 1; /** onFilterComplete timeout. */ - public static final int FILTER_COMPLETE_TIMEOUT_MS = 10 * 60 * 1000; //10 minutes + public static final int FILTER_COMPLETE_TIMEOUT_MS = 12 * 60 * 1000; //12 minutes /** SMS anomaly uuid -- CarrierMessagingService did not respond */ private static final UUID sAnomalyNoResponseFromCarrierMessagingService = @@ -381,7 +381,9 @@ public class CarrierServicesSmsFilter { } private void addToCallbacks(CarrierSmsFilterCallback callback) { - mCallbacks.add(callback); + synchronized (mFilterLock) { + mCallbacks.add(callback); + } } } diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java index 9cbd7a6174..bff1d41327 100644 --- a/src/java/com/android/internal/telephony/CellularNetworkService.java +++ b/src/java/com/android/internal/telephony/CellularNetworkService.java @@ -25,9 +25,11 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.AnomalyReporter; +import android.telephony.CarrierConfigManager; import android.telephony.CellIdentity; import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; @@ -42,6 +44,7 @@ import android.telephony.NetworkService; import android.telephony.NetworkServiceCallback; import android.telephony.NrVopsSupportInfo; import android.telephony.ServiceState; +import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.VopsSupportInfo; @@ -230,6 +233,10 @@ public class CellularNetworkService extends NetworkService { || regState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { if (domain == NetworkRegistrationInfo.DOMAIN_PS) { availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_DATA); + if (isMmsEnabled(mPhone)) { + // Add SERVICE_TYPE_MMS only if MMS is enabled + availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_MMS); + } } else if (domain == NetworkRegistrationInfo.DOMAIN_CS) { availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE); availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_SMS); @@ -279,27 +286,6 @@ public class CellularNetworkService extends NetworkService { } else if (result instanceof android.hardware.radio.V1_5.RegStateResult) { return getNetworkRegistrationInfo(domain, transportType, (android.hardware.radio.V1_5.RegStateResult) result); - } else if (result instanceof android.hardware.radio.V1_0.VoiceRegStateResult) { - android.hardware.radio.V1_0.VoiceRegStateResult voiceRegState = - (android.hardware.radio.V1_0.VoiceRegStateResult) result; - int regState = getRegStateFromHalRegState(voiceRegState.regState); - int networkType = ServiceState.rilRadioTechnologyToNetworkType(voiceRegState.rat); - int reasonForDenial = voiceRegState.reasonForDenial; - boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState); - boolean cssSupported = voiceRegState.cssSupported; - int roamingIndicator = voiceRegState.roamingIndicator; - int systemIsInPrl = voiceRegState.systemIsInPrl; - int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator; - List<Integer> availableServices = getAvailableServices( - regState, domain, emergencyOnly); - CellIdentity cellIdentity = - RILUtils.convertHalCellIdentity(voiceRegState.cellIdentity); - final String rplmn = getPlmnFromCellIdentity(cellIdentity); - - return new NetworkRegistrationInfo(domain, transportType, regState, - networkType, reasonForDenial, emergencyOnly, availableServices, - cellIdentity, rplmn, cssSupported, roamingIndicator, systemIsInPrl, - defaultRoamingIndicator); } else if (result instanceof android.hardware.radio.V1_2.VoiceRegStateResult) { android.hardware.radio.V1_2.VoiceRegStateResult voiceRegState = (android.hardware.radio.V1_2.VoiceRegStateResult) result; @@ -330,20 +316,6 @@ public class CellularNetworkService extends NetworkService { final int domain = NetworkRegistrationInfo.DOMAIN_PS; final int transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - int regState = NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; - int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - int reasonForDenial = 0; - boolean emergencyOnly = false; - int maxDataCalls = 0; - CellIdentity cellIdentity; - boolean isEndcAvailable = false; - boolean isNrAvailable = false; - boolean isDcNrRestricted = false; - - LteVopsSupportInfo lteVopsSupportInfo = - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, - LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE); - if (result instanceof android.hardware.radio.network.RegStateResult) { return getNetworkRegistrationInfoAidl(domain, transportType, (android.hardware.radio.network.RegStateResult) result); @@ -353,66 +325,46 @@ public class CellularNetworkService extends NetworkService { } else if (result instanceof android.hardware.radio.V1_5.RegStateResult) { return getNetworkRegistrationInfo(domain, transportType, (android.hardware.radio.V1_5.RegStateResult) result); - } else if (result instanceof android.hardware.radio.V1_0.DataRegStateResult) { - android.hardware.radio.V1_0.DataRegStateResult dataRegState = - (android.hardware.radio.V1_0.DataRegStateResult) result; - regState = getRegStateFromHalRegState(dataRegState.regState); - networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.rat); - reasonForDenial = dataRegState.reasonDataDenied; - emergencyOnly = isEmergencyOnly(dataRegState.regState); - maxDataCalls = dataRegState.maxDataCalls; - cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.cellIdentity); - } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) { - android.hardware.radio.V1_2.DataRegStateResult dataRegState = - (android.hardware.radio.V1_2.DataRegStateResult) result; - regState = getRegStateFromHalRegState(dataRegState.regState); - networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.rat); - reasonForDenial = dataRegState.reasonDataDenied; - emergencyOnly = isEmergencyOnly(dataRegState.regState); - maxDataCalls = dataRegState.maxDataCalls; - cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.cellIdentity); } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) { android.hardware.radio.V1_4.DataRegStateResult dataRegState = (android.hardware.radio.V1_4.DataRegStateResult) result; - regState = getRegStateFromHalRegState(dataRegState.base.regState); - networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.base.rat); - - reasonForDenial = dataRegState.base.reasonDataDenied; - emergencyOnly = isEmergencyOnly(dataRegState.base.regState); - maxDataCalls = dataRegState.base.maxDataCalls; - cellIdentity = RILUtils.convertHalCellIdentity(dataRegState.base.cellIdentity); - android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators; - + LteVopsSupportInfo lteVopsSupportInfo; // Check for lteVopsInfo only if its initialized and RAT is EUTRAN if (dataRegState.vopsInfo.getDiscriminator() == hidl_discriminator.lteVopsInfo && ServiceState.rilRadioTechnologyToAccessNetworkType(dataRegState.base.rat) == AccessNetworkType.EUTRAN) { android.hardware.radio.V1_4.LteVopsInfo vopsSupport = dataRegState.vopsInfo.lteVopsInfo(); - lteVopsSupportInfo = convertHalLteVopsSupportInfo(vopsSupport.isVopsSupported, - vopsSupport.isEmcBearerSupported); + lteVopsSupportInfo = convertHalLteVopsSupportInfo( + vopsSupport.isVopsSupported, vopsSupport.isEmcBearerSupported); } else { - lteVopsSupportInfo = - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, - LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE); + lteVopsSupportInfo = new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, + LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE); } - - isEndcAvailable = nrIndicators.isEndcAvailable; - isNrAvailable = nrIndicators.isNrAvailable; - isDcNrRestricted = nrIndicators.isDcNrRestricted; + int regState = getRegStateFromHalRegState(dataRegState.base.regState); + int networkType = + ServiceState.rilRadioTechnologyToNetworkType(dataRegState.base.rat); + int reasonForDenial = dataRegState.base.reasonDataDenied; + boolean emergencyOnly = isEmergencyOnly(dataRegState.base.regState); + int maxDataCalls = dataRegState.base.maxDataCalls; + CellIdentity cellIdentity = + RILUtils.convertHalCellIdentity(dataRegState.base.cellIdentity); + android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators; + boolean isEndcAvailable = nrIndicators.isEndcAvailable; + boolean isNrAvailable = nrIndicators.isNrAvailable; + boolean isDcNrRestricted = nrIndicators.isDcNrRestricted; + String rplmn = getPlmnFromCellIdentity(cellIdentity); + List<Integer> availableServices = getAvailableServices( + regState, domain, emergencyOnly); + return new NetworkRegistrationInfo(domain, transportType, regState, networkType, + reasonForDenial, emergencyOnly, availableServices, cellIdentity, rplmn, + maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, + lteVopsSupportInfo); } else { loge("Unknown type of DataRegStateResult " + result); return null; } - - String rplmn = getPlmnFromCellIdentity(cellIdentity); - List<Integer> availableServices = getAvailableServices( - regState, domain, emergencyOnly); - - return new NetworkRegistrationInfo(domain, transportType, regState, networkType, - reasonForDenial, emergencyOnly, availableServices, cellIdentity, rplmn, - maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, - lteVopsSupportInfo); } private @NonNull NetworkRegistrationInfo getNetworkRegistrationInfo( @@ -805,6 +757,23 @@ public class CellularNetworkService extends NetworkService { return new CellularNetworkServiceProvider(slotIndex); } + private boolean isMmsEnabled(Phone phone) { + CarrierConfigManager carrierConfigManager = phone.getContext() + .getSystemService(CarrierConfigManager.class); + if (carrierConfigManager != null) { + PersistableBundle config = carrierConfigManager.getConfigForSubId( + phone.getSubId(), SmsManager.MMS_CONFIG_MMS_ENABLED); + if (config == null || config.isEmpty()) { + config = CarrierConfigManager.getDefaultConfig(); + } + + return config.getBoolean(SmsManager.MMS_CONFIG_MMS_ENABLED); + } else { + loge("isMmsEnabled: CarrierConfigManager is null"); + return false; + } + } + private static void log(String s) { Rlog.d(TAG, s); } diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java index e068c1cbff..6b80e9f1d3 100644 --- a/src/java/com/android/internal/telephony/CommandException.java +++ b/src/java/com/android/internal/telephony/CommandException.java @@ -131,6 +131,17 @@ public class CommandException extends RuntimeException { BLOCKED_DUE_TO_CALL, RF_HARDWARE_ISSUE, NO_RF_CALIBRATION_INFO, + ENCODING_NOT_SUPPORTED, + FEATURE_NOT_SUPPORTED, + INVALID_CONTACT, + MODEM_INCOMPATIBLE, + NETWORK_TIMEOUT, + NO_SATELLITE_SIGNAL, + NOT_SUFFICIENT_ACCOUNT_BALANCE, + RADIO_TECHNOLOGY_NOT_SUPPORTED, + SUBSCRIBER_NOT_AUTHORIZED, + SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL, + UNIDENTIFIED_SUBSCRIBER } @UnsupportedAppUsage diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 971e051c5e..91e6fab171 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -74,7 +74,6 @@ public interface CommandsInterface { // Used as parameters for call forward methods below static final int CF_ACTION_DISABLE = 0; static final int CF_ACTION_ENABLE = 1; -// static final int CF_ACTION_UNUSED = 2; static final int CF_ACTION_REGISTRATION = 3; static final int CF_ACTION_ERASURE = 4; @@ -628,85 +627,85 @@ public interface CommandsInterface { @UnsupportedAppUsage void setEmergencyCallbackMode(Handler h, int what, Object obj); - /** - * Fires on any CDMA OTA provision status change - */ - @UnsupportedAppUsage - void registerForCdmaOtaProvision(Handler h,int what, Object obj); - @UnsupportedAppUsage - void unregisterForCdmaOtaProvision(Handler h); - - /** - * Registers the handler when out-band ringback tone is needed.<p> - * - * Messages received from this: - * Message.obj will be an AsyncResult - * AsyncResult.userObj = obj - * AsyncResult.result = boolean. <p> - */ - void registerForRingbackTone(Handler h, int what, Object obj); - void unregisterForRingbackTone(Handler h); - - /** - * Registers the handler when mute/unmute need to be resent to get - * uplink audio during a call.<p> - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - * - */ - void registerForResendIncallMute(Handler h, int what, Object obj); - void unregisterForResendIncallMute(Handler h); - - /** - * Registers the handler for when Cdma subscription changed events - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - * - */ - void registerForCdmaSubscriptionChanged(Handler h, int what, Object obj); - void unregisterForCdmaSubscriptionChanged(Handler h); - - /** - * Registers the handler for when Cdma prl changed events - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - * - */ - void registerForCdmaPrlChanged(Handler h, int what, Object obj); - void unregisterForCdmaPrlChanged(Handler h); - - /** - * Registers the handler for when Cdma prl changed events - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - * - */ - void registerForExitEmergencyCallbackMode(Handler h, int what, Object obj); - void unregisterForExitEmergencyCallbackMode(Handler h); - - /** - * Registers the handler for RIL_UNSOL_RIL_CONNECT events. - * - * When ril connects or disconnects a message is sent to the registrant - * which contains an AsyncResult, ar, in msg.obj. The ar.result is an - * Integer which is the version of the ril or -1 if the ril disconnected. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - void registerForRilConnected(Handler h, int what, Object obj); - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - void unregisterForRilConnected(Handler h); + /** + * Fires on any CDMA OTA provision status change + */ + @UnsupportedAppUsage + void registerForCdmaOtaProvision(Handler h, int what, Object obj); + @UnsupportedAppUsage + void unregisterForCdmaOtaProvision(Handler h); + + /** + * Registers the handler when out-band ringback tone is needed.<p> + * + * Messages received from this: + * Message.obj will be an AsyncResult + * AsyncResult.userObj = obj + * AsyncResult.result = boolean. <p> + */ + void registerForRingbackTone(Handler h, int what, Object obj); + void unregisterForRingbackTone(Handler h); + + /** + * Registers the handler when mute/unmute need to be resent to get + * uplink audio during a call.<p> + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + * + */ + void registerForResendIncallMute(Handler h, int what, Object obj); + void unregisterForResendIncallMute(Handler h); + + /** + * Registers the handler for when Cdma subscription changed events + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + * + */ + void registerForCdmaSubscriptionChanged(Handler h, int what, Object obj); + void unregisterForCdmaSubscriptionChanged(Handler h); + + /** + * Registers the handler for when Cdma prl changed events + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + * + */ + void registerForCdmaPrlChanged(Handler h, int what, Object obj); + void unregisterForCdmaPrlChanged(Handler h); + + /** + * Registers the handler for when Cdma prl changed events + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + * + */ + void registerForExitEmergencyCallbackMode(Handler h, int what, Object obj); + void unregisterForExitEmergencyCallbackMode(Handler h); + + /** + * Registers the handler for RIL_UNSOL_RIL_CONNECT events. + * + * When ril connects or disconnects a message is sent to the registrant + * which contains an AsyncResult, ar, in msg.obj. The ar.result is an + * Integer which is the version of the ril or -1 if the ril disconnected. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + void registerForRilConnected(Handler h, int what, Object obj); + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + void unregisterForRilConnected(Handler h); /** * Registers the handler for RIL_UNSOL_SIM_DETACH_FROM_NETWORK_CONFIG_CHANGED events. @@ -905,18 +904,6 @@ public interface CommandsInterface { * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of DataCallResponse - * @deprecated Do not use. - */ - @UnsupportedAppUsage - @Deprecated - void getPDPContextList(Message result); - - /** - * returned message - * retMsg.obj = AsyncResult ar - * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj - * ar.result contains a List of DataCallResponse */ @UnsupportedAppUsage void getDataCallList(Message result); @@ -933,7 +920,7 @@ public interface CommandsInterface { * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation) */ void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo, - boolean hasKnownUserIntentEmergency, int clirMode, Message result); + boolean hasKnownUserIntentEmergency, int clirMode, Message result); /** * returned message @@ -947,7 +934,7 @@ public interface CommandsInterface { * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation) */ void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo, - boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result); + boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result); /** * returned message @@ -969,25 +956,6 @@ public interface CommandsInterface { void getIMSIForApp(String aid, Message result); /** - * returned message - * retMsg.obj = AsyncResult ar - * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj - * ar.result is String containing IMEI on success - */ - void getIMEI(Message result); - - /** - * returned message - * retMsg.obj = AsyncResult ar - * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj - * ar.result is String containing IMEISV on success - */ - @UnsupportedAppUsage - void getIMEISV(Message result); - - /** * Hang up one individual connection. * returned message * retMsg.obj = AsyncResult ar @@ -1102,25 +1070,6 @@ public interface CommandsInterface { */ void getLastCallFailCause (Message result); - - /** - * Reason for last PDP context deactivate or failure to activate - * cause code returned as int[0] in Message.obj.response - * returns an integer cause code defined in TS 24.008 - * section 6.1.3.1.3 or close approximation - * @deprecated Do not use. - */ - @UnsupportedAppUsage - @Deprecated - void getLastPdpFailCause (Message result); - - /** - * The preferred new alternative to getLastPdpFailCause - * that is also CDMA-compatible. - */ - @UnsupportedAppUsage - void getLastDataCallFailCause (Message result); - void setMute (boolean enableMute, Message response); void getMute (Message response); @@ -1422,7 +1371,7 @@ public interface CommandsInterface { */ @UnsupportedAppUsage void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response); + String number, int timeSeconds, Message response); /** * cfReason is one of CF_REASON_* @@ -1500,7 +1449,7 @@ public interface CommandsInterface { @UnsupportedAppUsage void queryFacilityLock (String facility, String password, int serviceClass, - Message response); + Message response); /** * (AsyncResult)response.obj).result will be an Integer representing @@ -1515,7 +1464,7 @@ public interface CommandsInterface { */ void queryFacilityLockForApp(String facility, String password, int serviceClass, String appId, - Message response); + Message response); /** * @param facility one of CB_FACILTY_* @@ -1526,7 +1475,7 @@ public interface CommandsInterface { */ @UnsupportedAppUsage void setFacilityLock (String facility, boolean lockState, String password, - int serviceClass, Message response); + int serviceClass, Message response); /** * Set the facility lock for the app with this AID on the ICC card. @@ -1539,7 +1488,7 @@ public interface CommandsInterface { * @param response is callback message */ void setFacilityLockForApp(String facility, boolean lockState, String password, - int serviceClass, String appId, Message response); + int serviceClass, String appId, Message response); void sendUSSD (String ussdString, Message response); @@ -1549,8 +1498,6 @@ public interface CommandsInterface { */ void cancelPendingUssd (Message response); - void resetRadio(Message result); - /** * Assign a specified band for RF configuration. * @@ -1578,7 +1525,7 @@ public interface CommandsInterface { @UnsupportedAppUsage void setPreferredNetworkType(int networkType , Message response); - /** + /** * Query the preferred network type setting * * @param response is callback message to report one of NT_*_TYPE @@ -1595,7 +1542,7 @@ public interface CommandsInterface { void setAllowedNetworkTypesBitmap( @TelephonyManager.NetworkTypeBitMask int networkTypeBitmask, Message response); - /** + /** * Query the allowed network types setting. * * @param response is callback message to report allowed network types bitmask @@ -1681,28 +1628,14 @@ public interface CommandsInterface { @UnsupportedAppUsage void reportStkServiceIsRunning(Message result); - @UnsupportedAppUsage - void invokeOemRilRequestRaw(byte[] data, Message response); - /** * Sends carrier specific information to the vendor ril that can be used to * encrypt the IMSI and IMPI. * - * @param publicKey the public key of the carrier used to encrypt IMSI/IMPI. - * @param keyIdentifier the key identifier is optional information that is carrier - * specific. + * @param imsiEncryptionInfo the IMSI encryption info * @param response callback message */ - void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo, - Message response); - - void invokeOemRilRequestStrings(String[] strings, Message response); - - /** - * Fires when RIL_UNSOL_OEM_HOOK_RAW is received from the RIL. - */ - void setOnUnsolOemHookRaw(Handler h, int what, Object obj); - void unSetOnUnsolOemHookRaw(Handler h); + void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo, Message response); /** * Send TERMINAL RESPONSE to the SIM, after processing a proactive command @@ -1802,6 +1735,12 @@ public interface CommandsInterface { public void getImei(Message response); /** + * Register to listen for the changes in the primary IMEI with respect to the sim slot. + */ + + public void registerForImeiMappingChanged(Handler h, int what, Object obj); + + /** * Request the device MDN / H_SID / H_NID / MIN. * "response" is const char ** * [0] is MDN if CDMA subscription is available @@ -1879,15 +1818,13 @@ public interface CommandsInterface { void queryTTYMode(Message response); /** - * Setup a packet data connection On successful completion, the result + * Setup a packet data connection. On successful completion, the result * message will return a SetupDataResult object containing the connection information. * * @param accessNetworkType * Access network to use. Values is one of AccessNetworkConstants.AccessNetworkType. * @param dataProfile * Data profile for data call setup - * @param isRoaming - * Device is roaming or not * @param allowRoaming * Flag indicating data roaming is enabled or not * @param reason @@ -1918,9 +1855,9 @@ public interface CommandsInterface { * @param result * Callback message */ - void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, + void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean allowRoaming, + int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, Message result); /** @@ -1982,22 +1919,6 @@ public interface CommandsInterface { public void getIccCardStatus(Message result); /** - * Request the status of all the physical UICC slots. - * - * @param result Callback message containing a {@link java.util.ArrayList} of - * {@link com.android.internal.telephony.uicc.IccSlotStatus} instances for all the slots. - */ - void getIccSlotsStatus(Message result); - - /** - * Set the mapping from logical slots to physical slots. - * - * @param physicalSlots Mapping from logical slots to physical slots. - * @param result Callback message is empty on completion. - */ - void setLogicalToPhysicalSlotMapping(int[] physicalSlots, Message result); - - /** * Request the SIM application on the UICC to perform authentication * challenge/response algorithm. The data string and challenge response are * Base64 encoded Strings. @@ -2074,24 +1995,20 @@ public interface CommandsInterface { * * @param dataProfile * data profile for initial APN attach - * @param isRoaming - * indicating the device is roaming or not * @param result * callback message contains the information of SUCCESS/FAILURE */ - void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result); + void setInitialAttachApn(DataProfile dataProfile, Message result); /** * Set data profiles in modem * * @param dps * Array of the data profiles set to modem - * @param isRoaming - * Indicating if the device is roaming or not * @param result * callback message contains the information of SUCCESS/FAILURE */ - void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result); + void setDataProfile(DataProfile[] dps, Message result); /** * Notifiy that we are testing an emergency call @@ -2236,7 +2153,7 @@ public interface CommandsInterface { return HalVersion.UNKNOWN; } - /** + /** * Sets user selected subscription at Modem. * * @param slotId @@ -2256,15 +2173,6 @@ public interface CommandsInterface { Message result); /** - * Whether the device modem supports reporting the EID in either the slot or card status or - * through ATR. - * @return true if the modem supports EID. - */ - default boolean supportsEid() { - return false; - } - - /** * Tells the modem if data is allowed or not. * * @param allowed @@ -2318,34 +2226,6 @@ public interface CommandsInterface { public void unregisterForRadioCapabilityChanged(Handler h); /** - * Start LCE (Link Capacity Estimation) service with a desired reporting interval. - * - * @param reportIntervalMs - * LCE info reporting interval (ms). - * - * @param result Callback message contains the current LCE status. - * {byte status, int actualIntervalMs} - */ - public void startLceService(int reportIntervalMs, boolean pullMode, Message result); - - /** - * Stop LCE service. - * - * @param result Callback message contains the current LCE status: - * {byte status, int actualIntervalMs} - * - */ - public void stopLceService(Message result); - - /** - * Pull LCE service for capacity data. - * - * @param result Callback message contains the capacity info: - * {int capacityKbps, byte confidenceLevel, byte lceSuspendedTemporarily} - */ - public void pullLceData(Message result); - - /** * Register a LCE info listener. * * @param h Handler for notification message. @@ -2738,7 +2618,7 @@ public interface CommandsInterface { return true; }; - /** + /** * Return the class name of the currently bound modem service. * * @return the class name of the modem service. @@ -2747,18 +2627,18 @@ public interface CommandsInterface { return "default"; }; - /** + /** * Request the SIM phonebook records of all activated UICC applications * * @param result Callback message containing the count of ADN valid record. */ - public void getSimPhonebookRecords(Message result); + void getSimPhonebookRecords(Message result); - /** + /** * Request the SIM phonebook Capacity of all activated UICC applications * */ - public void getSimPhonebookCapacity(Message result); + void getSimPhonebookCapacity(Message result); /** * Request to insert/delete/update the SIM phonebook record @@ -2766,7 +2646,7 @@ public interface CommandsInterface { * @param phonebookRecordInfo adn record information to be updated * @param result Callback message containing the SIM phonebook record index. */ - public void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecordInfo, Message result); + void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecordInfo, Message result); /** * Registers the handler when the SIM phonebook is changed. @@ -2775,14 +2655,14 @@ public interface CommandsInterface { * @param what User-defined message code. * @param obj User object . */ - public void registerForSimPhonebookChanged(Handler h, int what, Object obj); + void registerForSimPhonebookChanged(Handler h, int what, Object obj); /** * Unregister for notifications when SIM phonebook has already init done. * * @param h Handler to be removed from the registrant list. */ - public void unregisterForSimPhonebookChanged(Handler h); + void unregisterForSimPhonebookChanged(Handler h); /** * Registers the handler when a group of SIM phonebook records received. @@ -2791,14 +2671,14 @@ public interface CommandsInterface { * @param what User-defined message code. * @param obj User object. */ - public void registerForSimPhonebookRecordsReceived(Handler h, int what, Object obj); + void registerForSimPhonebookRecordsReceived(Handler h, int what, Object obj); /** * Unregister for notifications when a group of SIM phonebook records received. * * @param h Handler to be removed from the registrant list. */ - public void unregisterForSimPhonebookRecordsReceived(Handler h); + void unregisterForSimPhonebookRecordsReceived(Handler h); /** * Registers for notifications of connection setup failure. @@ -3019,261 +2899,45 @@ public interface CommandsInterface { default void isN1ModeEnabled(Message result) {} /** - * Get feature capabilities supported by satellite. - * - * @param result Message that will be sent back to the requester - */ - default void getSatelliteCapabilities(Message result) {} - - /** - * Turn satellite modem on/off. - * - * @param result Message that will be sent back to the requester - * @param on {@code true} for turning on. - * {@code false} for turning off. - */ - default void setSatellitePower(Message result, boolean on) {} - - /** - * Get satellite modem state. - * - * @param result Message that will be sent back to the requester - */ - default void getSatellitePowerState(Message result) {} - - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - default void getSatelliteProvisionState(Message result) {} - - /** - * Check whether satellite modem is supported by the device. - * - * @param result Message that will be sent back to the requester - */ - default void isSatelliteSupported(Message result) {} - - /** - * Provision the subscription with a satellite provider. This is needed to register the - * subscription if the provider allows dynamic registration. - * - * @param result Message that will be sent back to the requester. - * @param imei IMEI of the SIM associated with the satellite modem. - * @param msisdn MSISDN of the SIM associated with the satellite modem. - * @param imsi IMSI of the SIM associated with the satellite modem. - * @param features List of features to be provisioned. - */ - default void provisionSatelliteService( - Message result, String imei, String msisdn, String imsi, int[] features) {} - - /** - * Add contacts that are allowed to be used for satellite communication. This is applicable for - * incoming messages as well. - * - * @param result Message that will be sent back to the requester. - * @param contacts List of allowed contacts to be added. - */ - default void addAllowedSatelliteContacts(Message result, String[] contacts) {} - - /** - * Remove contacts that are allowed to be used for satellite communication. This is applicable - * for incoming messages as well. - * - * @param result Message that will be sent back to the requester. - * @param contacts List of allowed contacts to be removed. - */ - default void removeAllowedSatelliteContacts(Message result, String[] contacts) {} - - /** - * Send text messages. - * - * @param result Message that will be sent back to the requester. - * @param messages List of messages in text format to be sent. - * @param destination The recipient of the message. - * @param latitude The current latitude of the device. - * @param longitude The current longitude of the device. The location (i.e., latitude and - * longitude) of the device will be filled for emergency messages. - */ - default void sendSatelliteMessages(Message result, String[] messages, String destination, - double latitude, double longitude) {} - - /** - * Get pending messages. - * - * @param result Message that will be sent back to the requester. - */ - default void getPendingSatelliteMessages(Message result) {} - - /** - * Get current satellite registration mode. - * - * @param result Message that will be sent back to the requester. - */ - default void getSatelliteMode(Message result) {} - - /** - * Set the filter for what type of indication framework want to receive from modem. - * - * @param result Message that will be sent back to the requester. - * @param filterBitmask The filter bitmask identifying what type of indication Telephony - * framework wants to receive from modem. - */ - default void setSatelliteIndicationFilter(Message result, int filterBitmask) {} - - /** - * User started pointing to the satellite. Modem should continue to update the ponting input - * as user moves device. - * - * @param result Message that will be sent back to the requester. - */ - default void startSendingSatellitePointingInfo(Message result) {} - - /** - * Stop sending satellite pointing info to the framework. - * - * @param result Message that will be sent back to the requester. - */ - default void stopSendingSatellitePointingInfo(Message result) {} - - /** - * Get max number of characters per text message. - * - * @param result Message that will be sent back to the requester. - */ - default void getMaxCharactersPerSatelliteTextMessage(Message result) {} - - /** - * Get whether satellite communication is allowed for the current location. - * - * @param result Message that will be sent back to the requester. - */ - default void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {} - - /** - * Get the time after which the satellite will be visible. - * - * @param result Message that will be sent back to the requester. - */ - default void getTimeForNextSatelliteVisibility(Message result) {} - - /** - * Registers for pending message count from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - default void registerForPendingSatelliteMessageCount(@NonNull Handler h, - int what, @Nullable Object obj) {} - - /** - * Unregisters for pending message count from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - default void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) {} - - /** - * Registers for new messages from satellite modem. + * Enables or disables cellular identifier disclosure transparency. * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - default void registerForNewSatelliteMessages(@NonNull Handler h, - int what, @Nullable Object obj) {} - - /** - * Unregisters for new messages from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - default void unregisterForNewSatelliteMessages(@NonNull Handler h) {} - - /** - * Registers for messages transfer complete from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - default void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, - int what, @Nullable Object obj) {} - - /** - * Unregisters for messages transfer complete from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - default void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) {} - - /** - * Registers for pointing info changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - default void registerForSatellitePointingInfoChanged(@NonNull Handler h, - int what, @Nullable Object obj) {} - - /** - * Unregisters for pointing info changed from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - default void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) {} - - /** - * Registers for mode changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. + * @param enable {@code true} to enable, {@code false} to disable. + * @param result Callback message to receive the result. */ - default void registerForSatelliteModeChanged(@NonNull Handler h, - int what, @Nullable Object obj) {} + default void setCellularIdentifierTransparencyEnabled(boolean enable, Message result) {} /** - * Unregisters for mode changed from satellite modem. + * Check whether cellular identifier transparency. * - * @param h Handler to be removed from the registrant list. + * @param result Callback message to receive the result. */ - default void unregisterForSatelliteModeChanged(@NonNull Handler h) {} + default void isCellularIdentifierTransparencyEnabled(Message result) {} /** - * Registers for radio technology changed from satellite modem. + * Enables or disables security algorithm update reports. * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. + * @param enable {@code true} to enable, {@code false} to disable. + * @param result Callback message to receive the result. */ - default void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h, - int what, @Nullable Object obj) {} + default void setSecurityAlgorithmsUpdatedEnabled(boolean enable, Message result) {} /** - * Unregisters for radio technology changed from satellite modem. + * Check whether security algorithm update reports are enabled. * - * @param h Handler to be removed from the registrant list. + * @param result Callback message to receive the result. */ - default void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) {} + default void isSecurityAlgorithmsUpdatedEnabled(Message result) {} /** - * Registers for provision state changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. + * Registers for cellular identifier disclosure events. */ - default void registerForSatelliteProvisionStateChanged(@NonNull Handler h, - int what, @Nullable Object obj) {} + default void registerForCellularIdentifierDisclosures( + @NonNull Handler h, int what, @Nullable Object obj) {} /** - * Unregisters for provision state changed from satellite modem. + * Unregisters for cellular identifier disclosure events. * * @param h Handler to be removed from the registrant list. */ - default void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {} + default void unregisterForCellularIdentifierDisclosures(@NonNull Handler h) {} } diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index e5a5c8fd88..c035329a07 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -41,6 +41,7 @@ import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.MediaQualityStatus; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; import java.util.List; @@ -55,10 +56,15 @@ public class DefaultPhoneNotifier implements PhoneNotifier { private TelephonyRegistryManager mTelephonyRegistryMgr; + /** Feature flags */ + @NonNull + private final FeatureFlags mFeatureFlags; - public DefaultPhoneNotifier(Context context) { + + public DefaultPhoneNotifier(Context context, @NonNull FeatureFlags featureFlags) { mTelephonyRegistryMgr = (TelephonyRegistryManager) context.getSystemService( Context.TELEPHONY_REGISTRY_SERVICE); + mFeatureFlags = featureFlags; } @Override @@ -125,8 +131,16 @@ public class DefaultPhoneNotifier implements PhoneNotifier { @Override public void notifyDataActivity(Phone sender) { + int subId = sender.getSubId(); - mTelephonyRegistryMgr.notifyDataActivityChanged(subId, sender.getDataActivityState()); + + if (mFeatureFlags.notifyDataActivityChangedWithSlot()) { + int phoneId = sender.getPhoneId(); + mTelephonyRegistryMgr.notifyDataActivityChanged(phoneId, subId, + sender.getDataActivityState()); + } else { + mTelephonyRegistryMgr.notifyDataActivityChanged(subId, sender.getDataActivityState()); + } } @Override diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java index ecc6208192..7bdf2ff655 100644 --- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java +++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java @@ -22,6 +22,7 @@ import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED; import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; +import android.annotation.NonNull; import android.app.UiModeManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -47,6 +48,7 @@ import android.util.LocalLog; import android.view.Display; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -92,10 +94,14 @@ public class DeviceStateMonitor extends Handler { private static final int NR_NSA_TRACKING_INDICATIONS_ALWAYS_ON = 2; private final Phone mPhone; + @NonNull + private final FeatureFlags mFeatureFlags; private final LocalLog mLocalLog = new LocalLog(64); private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList(); + private final RegistrantList mSignalStrengthReportDecisionCallbackRegistrants = + new RegistrantList(); private final NetworkRequest mWifiNetworkRequest = new NetworkRequest.Builder() @@ -269,8 +275,9 @@ public class DeviceStateMonitor extends Handler { * * @param phone Phone object */ - public DeviceStateMonitor(Phone phone) { + public DeviceStateMonitor(Phone phone, @NonNull FeatureFlags featureFlags) { mPhone = phone; + mFeatureFlags = featureFlags; DisplayManager dm = (DisplayManager) phone.getContext().getSystemService( Context.DISPLAY_SERVICE); dm.registerDisplayListener(mDisplayListener, null); @@ -602,6 +609,15 @@ public class DeviceStateMonitor extends Handler { // use a null message since we don't care of receiving response mPhone.mCi.getBarringInfo(null); } + + // Determine whether to notify registrants about the non-terrestrial signal strength change. + if (mFeatureFlags.oemEnabledSatelliteFlag()) { + if (shouldEnableSignalStrengthReports()) { + mSignalStrengthReportDecisionCallbackRegistrants.notifyResult(true); + } else { + mSignalStrengthReportDecisionCallbackRegistrants.notifyResult(false); + } + } } /** @@ -778,6 +794,33 @@ public class DeviceStateMonitor extends Handler { } /** + * Register a callback to decide whether signal strength should be notified or not. + * @param h Handler to notify + * @param what msg.what when the message is delivered + * @param obj AsyncResult.userObj when the message is delivered + */ + public void registerForSignalStrengthReportDecision(Handler h, int what, Object obj) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + Rlog.d(TAG, "oemEnabledSatelliteFlag is disabled"); + return; + } + Registrant r = new Registrant(h, what, obj); + mSignalStrengthReportDecisionCallbackRegistrants.add(r); + } + + /** + * Register a callback to decide whether signal strength should be notified or not. + * @param h Handler to notify + */ + public void unregisterForSignalStrengthReportDecision(Handler h) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + Rlog.d(TAG, "oemEnabledSatelliteFlag is disabled"); + return; + } + mSignalStrengthReportDecisionCallbackRegistrants.remove(h); + } + + /** * @param msg Debug message * @param logIntoLocalLog True if log into the local log */ diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java index 567331d459..945b640433 100644 --- a/src/java/com/android/internal/telephony/DisplayInfoController.java +++ b/src/java/com/android/internal/telephony/DisplayInfoController.java @@ -19,9 +19,11 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.os.Handler; import android.os.Message; +import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.telephony.AnomalyReporter; +import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; @@ -29,6 +31,7 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Pair; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -66,34 +69,55 @@ public class DisplayInfoController extends Handler { /** Event for service state changed (roaming). */ private static final int EVENT_SERVICE_STATE_CHANGED = 1; + /** Event for carrier config changed. */ + private static final int EVENT_CARRIER_CONFIG_CHANGED = 2; - private final Phone mPhone; - private final NetworkTypeController mNetworkTypeController; - private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = new RegistrantList(); - private @NonNull TelephonyDisplayInfo mTelephonyDisplayInfo; - private @NonNull ServiceState mServiceState; + @NonNull private final Phone mPhone; + @NonNull private final NetworkTypeController mNetworkTypeController; + @NonNull private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = + new RegistrantList(); + @NonNull private final FeatureFlags mFeatureFlags; + @NonNull private TelephonyDisplayInfo mTelephonyDisplayInfo; + @NonNull private ServiceState mServiceState; + @NonNull private PersistableBundle mConfigs; - public DisplayInfoController(Phone phone) { + public DisplayInfoController(@NonNull Phone phone, @NonNull FeatureFlags featureFlags) { mPhone = phone; + mFeatureFlags = featureFlags; mLogTag = "DIC-" + mPhone.getPhoneId(); + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + mConfigs = new PersistableBundle(); + try { + mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class) + .getConfigForSubId(mPhone.getSubId(), + CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL); + } catch (Exception ignored) { + // CarrierConfigLoader might not be available yet. + // Once it's available, configs will be updated through the listener. + } + mPhone.getServiceStateTracker() + .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); + mPhone.getContext().getSystemService(CarrierConfigManager.class) + .registerCarrierConfigChangeListener(Runnable::run, + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex == mPhone.getPhoneId()) { + obtainMessage(EVENT_CARRIER_CONFIG_CHANGED).sendToTarget(); + } + }); mTelephonyDisplayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_UNKNOWN, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, + false); mNetworkTypeController = new NetworkTypeController(phone, this); + // EVENT_UPDATE will transition from DefaultState to the current state + // and update the TelephonyDisplayInfo based on the current state. mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - - mServiceState = mPhone.getServiceStateTracker().getServiceState(); - post(() -> { - mPhone.getServiceStateTracker() - .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); - updateTelephonyDisplayInfo(); - }); } /** * @return the current TelephonyDisplayInfo */ - public @NonNull TelephonyDisplayInfo getTelephonyDisplayInfo() { + @NonNull public TelephonyDisplayInfo getTelephonyDisplayInfo() { return mTelephonyDisplayInfo; } @@ -105,7 +129,7 @@ public class DisplayInfoController extends Handler { TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo( mNetworkTypeController.getDataNetworkType(), mNetworkTypeController.getOverrideNetworkType(), - mServiceState.getRoaming()); + isRoaming()); if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) { logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to " + newDisplayInfo); @@ -117,6 +141,24 @@ public class DisplayInfoController extends Handler { } /** + * Determine the roaming status for icon display only. + * If this is {@code true}, the roaming indicator will be shown, and if this is {@code false}, + * the roaming indicator will not be shown. + * To get the actual roaming status, use {@link ServiceState#getRoaming()} instead. + * + * @return Whether the device is considered roaming for display purposes. + */ + private boolean isRoaming() { + boolean roaming = mServiceState.getRoaming(); + if (roaming && mFeatureFlags.hideRoamingIcon() + && !mConfigs.getBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL)) { + logl("Override roaming for display due to carrier configs."); + roaming = false; + } + return roaming; + } + + /** * Validate the display info and trigger anomaly report if needed. * * @param displayInfo The display info to validate. @@ -175,6 +217,13 @@ public class DisplayInfoController extends Handler { log("ServiceState updated, isRoaming=" + mServiceState.getRoaming()); updateTelephonyDisplayInfo(); break; + case EVENT_CARRIER_CONFIG_CHANGED: + mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class) + .getConfigForSubId(mPhone.getSubId(), + CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL); + log("Carrier configs updated: " + mConfigs); + updateTelephonyDisplayInfo(); + break; } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 6e2601e635..620b8711e2 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -80,6 +80,7 @@ import android.telephony.BarringInfo; import android.telephony.CarrierConfigManager; import android.telephony.CellBroadcastIdRange; import android.telephony.CellIdentity; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.ImsiEncryptionInfo; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkScanRequest; @@ -107,6 +108,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; import com.android.internal.telephony.gsm.SuppServiceNotification; @@ -115,6 +117,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.imsphone.ImsPhoneMmiCode; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; import com.android.internal.telephony.test.SimulatedRadioControl; @@ -182,11 +185,6 @@ public class GsmCdmaPhone extends Phone { private static final String VM_NUMBER_CDMA = "vm_number_key_cdma"; public static final int RESTART_ECM_TIMER = 0; // restart Ecm timer public static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer - private static final String PREFIX_WPS = "*272"; - // WPS prefix when CLIR is being deactivated for the call. - private static final String PREFIX_WPS_CLIR_DEACTIVATE = "#31#*272"; - // WPS prefix when CLIS is being activated for the call. - private static final String PREFIX_WPS_CLIR_ACTIVATE = "*31#*272"; private CdmaSubscriptionSourceManager mCdmaSSM; public int mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN; private PowerManager.WakeLock mWakeLock; @@ -256,6 +254,7 @@ public class GsmCdmaPhone extends Phone { CellBroadcastConfigTracker.make(this, null, true); private boolean mIsNullCipherAndIntegritySupported = false; + private boolean mIsIdentifierDisclosureTransparencySupported = false; // Create Cfu (Call forward unconditional) so that dialing number & // mOnComplete (Message object passed by client) can be packed & @@ -302,32 +301,48 @@ public class GsmCdmaPhone extends Phone { private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener; private final CallWaitingController mCallWaitingController; + private CellularIdentifierDisclosureNotifier mIdentifierDisclosureNotifier; + + // Set via Carrier Config + private boolean mIsN1ModeAllowedByCarrier = true; + // Set via a call to the method on Phone; the only caller is IMS, and all of this code will + // need to be updated to a voting mechanism (...enabled for reason...) if additional callers + // are desired. + private boolean mIsN1ModeAllowedByIms = true; + // If this value is null, then the modem value is unknown. If a caller explicitly sets the + // N1 mode, this value will be initialized before any attempt to set the value in the modem. + private Boolean mModemN1Mode = null; + // Constructors public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, - int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) { - this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory); + int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory, + @NonNull FeatureFlags featureFlags) { + this(context, ci, notifier, false, phoneId, precisePhoneType, telephonyComponentFactory, + featureFlags); } public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, - TelephonyComponentFactory telephonyComponentFactory) { + TelephonyComponentFactory telephonyComponentFactory, + @NonNull FeatureFlags featureFlags) { this(context, ci, notifier, unitTestMode, phoneId, precisePhoneType, telephonyComponentFactory, - ImsManager::getInstance); + ImsManager::getInstance, featureFlags); } public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory, - ImsManagerFactory imsManagerFactory) { + ImsManagerFactory imsManagerFactory, @NonNull FeatureFlags featureFlags) { super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA", - notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory); + notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory, + featureFlags); // phone type needs to be set before other initialization as other objects rely on it mPrecisePhoneType = precisePhoneType; - mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this); + mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this, featureFlags); mImsManagerFactory = imsManagerFactory; initOnce(ci); initRatSpecific(precisePhoneType); @@ -344,21 +359,22 @@ public class GsmCdmaPhone extends Phone { mSignalStrengthController = mTelephonyComponentFactory.inject( SignalStrengthController.class.getName()).makeSignalStrengthController(this); mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName()) - .makeServiceStateTracker(this, this.mCi); + .makeServiceStateTracker(this, this.mCi, featureFlags); mEmergencyNumberTracker = mTelephonyComponentFactory .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker( this, this.mCi); mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName()) - .makeDeviceStateMonitor(this); + .makeDeviceStateMonitor(this, mFeatureFlags); // DisplayInfoController creates an OverrideNetworkTypeController, which uses // DeviceStateMonitor so needs to be crated after it is instantiated. mDisplayInfoController = mTelephonyComponentFactory.inject( - DisplayInfoController.class.getName()).makeDisplayInfoController(this); + DisplayInfoController.class.getName()) + .makeDisplayInfoController(this, featureFlags); mDataNetworkController = mTelephonyComponentFactory.inject( DataNetworkController.class.getName()) - .makeDataNetworkController(this, getLooper()); + .makeDataNetworkController(this, getLooper(), featureFlags); mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName()) .makeCarrierResolver(this); @@ -453,7 +469,7 @@ public class GsmCdmaPhone extends Phone { mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mIccSmsInterfaceManager = mTelephonyComponentFactory .inject(IccSmsInterfaceManager.class.getName()) - .makeIccSmsInterfaceManager(this); + .makeIccSmsInterfaceManager(this, mFeatureFlags); mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); @@ -500,9 +516,24 @@ public class GsmCdmaPhone extends Phone { mContext.registerReceiver(mBroadcastReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, null, Context.RECEIVER_EXPORTED); - mCDM = new CarrierKeyDownloadManager(this); + mCDM = new CarrierKeyDownloadManager(this, mFeatureFlags); mCIM = new CarrierInfoManager(); + mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null); + + if (mFeatureFlags.enableIdentifierDisclosureTransparency()) { + logi( + "enable_identifier_disclosure_transparency is on. Registering for cellular " + + "identifier disclosures from phone " + + getPhoneId()); + mIdentifierDisclosureNotifier = + mTelephonyComponentFactory + .inject(CellularIdentifierDisclosureNotifier.class.getName()) + .makeIdentifierDisclosureNotifier(); + mCi.registerForCellularIdentifierDisclosures( + this, EVENT_CELL_IDENTIFIER_DISCLOSURE, null); + } + initializeCarrierApps(); } @@ -1415,9 +1446,7 @@ public class GsmCdmaPhone extends Phone { } /** Check if the call is Wireless Priority Service call */ - boolean isWpsCall = dialString != null ? (dialString.startsWith(PREFIX_WPS) - || dialString.startsWith(PREFIX_WPS_CLIR_ACTIVATE) - || dialString.startsWith(PREFIX_WPS_CLIR_DEACTIVATE)) : false; + boolean isWpsCall = PhoneNumberUtils.isWpsCallNumber(dialString); ImsPhone.ImsDialArgs.Builder imsDialArgsBuilder; imsDialArgsBuilder = ImsPhone.ImsDialArgs.Builder.from(dialArgs) @@ -1864,15 +1893,15 @@ public class GsmCdmaPhone extends Phone { String spName = isPhoneTypeGsm() ? VM_NUMBER : VM_NUMBER_CDMA; number = sp.getString(spName + getPhoneId(), null); logd("getVoiceMailNumber: from " + spName + " number=" - + Rlog.pii(LOG_TAG, number)); + + Rlog.piiHandle(number)); } else { - logd("getVoiceMailNumber: from IccRecords number=" + Rlog.pii(LOG_TAG, number)); + logd("getVoiceMailNumber: from IccRecords number=" + Rlog.piiHandle(number)); } } if (!isPhoneTypeGsm() && TextUtils.isEmpty(number)) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); number = sp.getString(VM_NUMBER_CDMA + getPhoneId(), null); - logd("getVoiceMailNumber: from VM_NUMBER_CDMA number=" + number); + logd("getVoiceMailNumber: from VM_NUMBER_CDMA number=" + Rlog.piiHandle(number)); } if (TextUtils.isEmpty(number)) { @@ -1894,9 +1923,13 @@ public class GsmCdmaPhone extends Phone { && !mSST.isImsRegistered()) { // roaming and IMS unregistered case if CC configured number = defaultVmNumberRoamingAndImsUnregistered; + logd("getVoiceMailNumber: from defaultVmNumberRoamingAndImsUnregistered " + + "number=" + Rlog.piiHandle(number)); } else if (!TextUtils.isEmpty(defaultVmNumberRoaming)) { // roaming default case if CC configured number = defaultVmNumberRoaming; + logd("getVoiceMailNumber: from defaultVmNumberRoaming number=" + + Rlog.piiHandle(number)); } } } @@ -1910,12 +1943,13 @@ public class GsmCdmaPhone extends Phone { if (b != null && b.getBoolean( CarrierConfigManager.KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL)) { number = getLine1Number(); + logd("getVoiceMailNumber: from MSISDN number=" + Rlog.piiHandle(number)); } } - return number; } + private String getVmSimImsi() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); return sp.getString(VM_SIM_IMSI + getPhoneId(), null); @@ -2349,11 +2383,76 @@ public class GsmCdmaPhone extends Phone { return false; } - private void updateSsOverCdmaSupported(PersistableBundle b) { - if (b == null) return; + private void updateSsOverCdmaSupported(@NonNull PersistableBundle b) { mSsOverCdmaSupported = b.getBoolean(CarrierConfigManager.KEY_SUPPORT_SS_OVER_CDMA_BOOL); } + /** + * Enables or disables N1 mode (access to 5G core network) in accordance with + * 3GPP TS 24.501 4.9. + * + * <p> To prevent redundant calls down to the modem and to support a mechanism whereby + * N1 mode is only on if both IMS and carrier config believe that it should be on, this + * method will first sync the value from the modem prior to possibly setting it. In addition + * N1 mode will not be set to enabled unless both IMS and Carrier want it, since the use + * cases require all entities to agree lest it default to disabled. + * + * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode. + * @param result Callback message to receive the result or null. + */ + @Override + public void setN1ModeEnabled(boolean enable, @Nullable Message result) { + if (mFeatureFlags.enableCarrierConfigN1Control()) { + // This might be called by IMS on another thread, so to avoid the requirement to + // lock, post it through the handler. + post(() -> { + mIsN1ModeAllowedByIms = enable; + if (mModemN1Mode == null) { + mCi.isN1ModeEnabled(obtainMessage(EVENT_GET_N1_MODE_ENABLED_DONE, result)); + } else { + maybeUpdateModemN1Mode(result); + } + }); + } else { + super.setN1ModeEnabled(enable, result); + } + } + + /** Only called on the handler thread. */ + private void maybeUpdateModemN1Mode(@Nullable Message result) { + final boolean wantN1Enabled = mIsN1ModeAllowedByCarrier && mIsN1ModeAllowedByIms; + + logd("N1 Mode: isModemN1Enabled=" + mModemN1Mode + ", wantN1Enabled=" + wantN1Enabled); + + // mModemN1Mode is never null here + if (mModemN1Mode != wantN1Enabled) { + // Assume success pending a response, which avoids multiple concurrent requests + // going down to the modem. If it fails, that is addressed in the response. + mModemN1Mode = wantN1Enabled; + super.setN1ModeEnabled( + wantN1Enabled, obtainMessage(EVENT_SET_N1_MODE_ENABLED_DONE, result)); + } else if (result != null) { + AsyncResult.forMessage(result); + result.sendToTarget(); + } + } + + /** Only called on the handler thread. */ + private void updateCarrierN1ModeSupported(@NonNull PersistableBundle b) { + if (!mFeatureFlags.enableCarrierConfigN1Control()) return; + + final int[] supportedNrModes = b.getIntArray( + CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); + + mIsN1ModeAllowedByCarrier = ArrayUtils.contains( + supportedNrModes, CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA); + if (mModemN1Mode == null) { + mCi.isN1ModeEnabled(obtainMessage(EVENT_GET_N1_MODE_ENABLED_DONE)); + } else { + maybeUpdateModemN1Mode(null); + } + } + @Override public boolean useSsOverIms(Message onComplete) { boolean isUtEnabled = isUtEnabled(); @@ -3046,7 +3145,7 @@ public class GsmCdmaPhone extends Phone { mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE)); handleNullCipherEnabledChange(); - startLceAfterRadioIsAvailable(); + handleIdentifierDisclosureNotificationPreferenceChange(); } private void handleRadioOn() { @@ -3092,19 +3191,7 @@ public class GsmCdmaPhone extends Phone { } break; case EVENT_GET_DEVICE_IMEI_DONE : - ar = (AsyncResult)msg.obj; - if (ar.exception != null || ar.result == null) { - loge("Exception received : " + ar.exception); - break; - } - ImeiInfo imeiInfo = (ImeiInfo) ar.result; - if (!TextUtils.isEmpty(imeiInfo.imei)) { - mImeiType = imeiInfo.type; - mImei = imeiInfo.imei; - mImeiSv = imeiInfo.svn; - } else { - // TODO Report telephony anomaly - } + parseImeiInfo(msg); break; case EVENT_GET_DEVICE_IDENTITY_DONE:{ ar = (AsyncResult)msg.obj; @@ -3218,15 +3305,17 @@ public class GsmCdmaPhone extends Phone { CarrierConfigManager configMgr = (CarrierConfigManager) getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = configMgr.getConfigForSubId(getSubId()); - - updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged(b); - - updateCdmaRoamingSettingsAfterCarrierConfigChanged(b); - - updateNrSettingsAfterCarrierConfigChanged(b); - updateVoNrSettings(b); - updateSsOverCdmaSupported(b); + final PersistableBundle b = configMgr.getConfigForSubId(getSubId()); + if (b != null) { + updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged(b); + updateCdmaRoamingSettingsAfterCarrierConfigChanged(b); + updateNrSettingsAfterCarrierConfigChanged(b); + updateVoNrSettings(b); + updateSsOverCdmaSupported(b); + updateCarrierN1ModeSupported(b); + } else { + loge("Failed to retrieve a carrier config bundle for subId=" + getSubId()); + } loadAllowedNetworksFromSubscriptionDatabase(); // Obtain new radio capabilities from the modem, since some are SIM-dependent mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); @@ -3523,14 +3612,7 @@ public class GsmCdmaPhone extends Phone { case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE: logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE"); ar = (AsyncResult) msg.obj; - // Only test for a success here in order to flip the support flag. - // Testing for the negative case, e.g. REQUEST_NOT_SUPPORTED, is insufficient - // because the modem or the RIL could still return exceptions for temporary - // failures even when the feature is unsupported. - if (ar == null || ar.exception == null) { - mIsNullCipherAndIntegritySupported = true; - return; - } + mIsNullCipherAndIntegritySupported = doesResultIndicateModemSupport(ar); break; case EVENT_IMS_DEREGISTRATION_TRIGGERED: @@ -3553,11 +3635,102 @@ public class GsmCdmaPhone extends Phone { } } break; + + case EVENT_GET_N1_MODE_ENABLED_DONE: + logd("EVENT_GET_N1_MODE_ENABLED_DONE"); + ar = (AsyncResult) msg.obj; + if (ar == null || ar.exception != null + || ar.result == null || !(ar.result instanceof Boolean)) { + Rlog.e(LOG_TAG, "Failed to Retrieve N1 Mode", ar.exception); + if (ar != null && ar.userObj instanceof Message) { + // original requester's message is stashed in the userObj + final Message rsp = (Message) ar.userObj; + AsyncResult.forMessage(rsp, null, ar.exception); + rsp.sendToTarget(); + } + break; + } + + mModemN1Mode = (Boolean) ar.result; + maybeUpdateModemN1Mode((Message) ar.userObj); + break; + + case EVENT_SET_N1_MODE_ENABLED_DONE: + logd("EVENT_SET_N1_MODE_ENABLED_DONE"); + ar = (AsyncResult) msg.obj; + if (ar == null || ar.exception != null) { + Rlog.e(LOG_TAG, "Failed to Set N1 Mode", ar.exception); + // Set failed, so we have no idea at this point. + mModemN1Mode = null; + } + if (ar != null && ar.userObj instanceof Message) { + // original requester's message is stashed in the userObj + final Message rsp = (Message) ar.userObj; + AsyncResult.forMessage(rsp, null, ar.exception); + rsp.sendToTarget(); + } + break; + + case EVENT_IMEI_MAPPING_CHANGED: + logd("EVENT_GET_DEVICE_IMEI_CHANGE_DONE phoneId = " + getPhoneId()); + parseImeiInfo(msg); + break; + + case EVENT_CELL_IDENTIFIER_DISCLOSURE: + logd("EVENT_CELL_IDENTIFIER_DISCLOSURE phoneId = " + getPhoneId()); + + ar = (AsyncResult) msg.obj; + if (ar == null || ar.result == null || ar.exception != null) { + Rlog.e( + LOG_TAG, + "Failed to process cellular identifier disclosure", + ar.exception); + break; + } + + CellularIdentifierDisclosure disclosure = (CellularIdentifierDisclosure) ar.result; + if (mFeatureFlags.enableIdentifierDisclosureTransparency() + && mIdentifierDisclosureNotifier != null + && disclosure != null) { + mIdentifierDisclosureNotifier.addDisclosure(disclosure); + } + break; + + case EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE: + logd("EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE"); + ar = (AsyncResult) msg.obj; + mIsIdentifierDisclosureTransparencySupported = doesResultIndicateModemSupport(ar); + break; + default: super.handleMessage(msg); } } + private boolean doesResultIndicateModemSupport(AsyncResult ar) { + // We can only say that the modem supports a call without ambiguity if there + // is no exception set on the response. Testing for REQUEST_NOT_SUPPORTED, is + // insufficient because the modem or the RIL could still return exceptions for temporary + // failures even when the feature is unsupported. + return (ar == null || ar.exception == null); + } + + private void parseImeiInfo(Message msg) { + AsyncResult ar = (AsyncResult)msg.obj; + if (ar.exception != null || ar.result == null) { + loge("parseImeiInfo :: Exception received : " + ar.exception); + return; + } + ImeiInfo imeiInfo = (ImeiInfo) ar.result; + if (!TextUtils.isEmpty(imeiInfo.imei)) { + mImeiType = imeiInfo.type; + mImei = imeiInfo.imei; + mImeiSv = imeiInfo.svn; + } else { + loge("parseImeiInfo :: IMEI value is empty"); + } + } + /** * Check if a different SIM is inserted at this slot from the last time. Storing last subId * in SharedPreference for now to detect SIM change. @@ -4408,7 +4581,6 @@ public class GsmCdmaPhone extends Phone { } else { loge("deleteAndCreatePhone: newVoiceRadioTech=" + newVoiceRadioTech + " is not CDMA or GSM (error) - aborting!"); - return; } } @@ -4995,12 +5167,7 @@ public class GsmCdmaPhone extends Phone { } private void updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged( - PersistableBundle config) { - if (config == null) { - loge("didn't get broadcastEmergencyCallStateChanges from carrier config"); - return; - } - + @NonNull PersistableBundle config) { // get broadcastEmergencyCallStateChanges boolean broadcastEmergencyCallStateChanges = config.getBoolean( CarrierConfigManager.KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL); @@ -5008,33 +5175,17 @@ public class GsmCdmaPhone extends Phone { setBroadcastEmergencyCallStateChanges(broadcastEmergencyCallStateChanges); } - private void updateNrSettingsAfterCarrierConfigChanged(PersistableBundle config) { - if (config == null) { - loge("didn't get the carrier_nr_availability_int from the carrier config."); - return; - } + private void updateNrSettingsAfterCarrierConfigChanged(@NonNull PersistableBundle config) { int[] nrAvailabilities = config.getIntArray( CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); mIsCarrierNrSupported = !ArrayUtils.isEmpty(nrAvailabilities); } - private void updateVoNrSettings(PersistableBundle config) { - UiccSlot slot = mUiccController.getUiccSlotForPhone(mPhoneId); - - // If no card is present, do nothing. - if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT) { - return; - } - + private void updateVoNrSettings(@NonNull PersistableBundle config) { if (mSimState != TelephonyManager.SIM_STATE_LOADED) { return; } - if (config == null) { - loge("didn't get the vonr_enabled_bool from the carrier config."); - return; - } - boolean mIsVonrEnabledByCarrier = config.getBoolean(CarrierConfigManager.KEY_VONR_ENABLED_BOOL); boolean mDefaultVonr = @@ -5059,12 +5210,8 @@ public class GsmCdmaPhone extends Phone { mCi.setVoNrEnabled(enbleVonr, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); } - private void updateCdmaRoamingSettingsAfterCarrierConfigChanged(PersistableBundle config) { - if (config == null) { - loge("didn't get the cdma_roaming_mode changes from the carrier config."); - return; - } - + private void updateCdmaRoamingSettingsAfterCarrierConfigChanged( + @NonNull PersistableBundle config) { // Changing the cdma roaming settings based carrier config. int config_cdma_roaming_mode = config.getInt( CarrierConfigManager.KEY_CDMA_ROAMING_MODE_INT); @@ -5160,7 +5307,31 @@ public class GsmCdmaPhone extends Phone { } @Override + public void handleIdentifierDisclosureNotificationPreferenceChange() { + if (!mFeatureFlags.enableIdentifierDisclosureTransparency()) { + logi("Not handling identifier disclosure preference change. Feature flag " + + "ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY disabled"); + return; + } + boolean prefEnabled = getIdentifierDisclosureNotificationsPreferenceEnabled(); + + if (prefEnabled) { + mIdentifierDisclosureNotifier.enable(); + } else { + mIdentifierDisclosureNotifier.disable(); + } + + mCi.setCellularIdentifierTransparencyEnabled(prefEnabled, + obtainMessage(EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE)); + } + + @Override public boolean isNullCipherAndIntegritySupported() { return mIsNullCipherAndIntegritySupported; } + + @Override + public boolean isIdentifierDisclosureTransparencySupported() { + return mIsIdentifierDisclosureTransparencySupported; + } } diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java index 2d7763179c..7c1670c48e 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -21,6 +21,7 @@ import static android.telephony.SmsManager.STATUS_ON_ICC_READ; import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD; import android.Manifest; +import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -47,6 +48,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.uicc.IccConstants; import com.android.internal.telephony.uicc.IccFileHandler; @@ -155,11 +157,11 @@ public class IccSmsInterfaceManager { } }; - protected IccSmsInterfaceManager(Phone phone) { + protected IccSmsInterfaceManager(Phone phone, @NonNull FeatureFlags featureFlags) { this(phone, phone.getContext(), (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE), new SmsDispatchersController( - phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor), + phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor, featureFlags), new SmsPermissions(phone, phone.getContext(), (AppOpsManager) phone.getContext().getSystemService( Context.APP_OPS_SERVICE))); diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index 9b116b4228..4e4d55d34b 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -39,6 +39,8 @@ import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.analytics.TelephonyAnalytics; +import com.android.internal.telephony.analytics.TelephonyAnalytics.SmsMmsAnalytics; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.util.SMSDispatcherUtil; @@ -200,10 +202,13 @@ public class ImsSmsDispatcher extends SMSDispatcher { tracker.onSent(mContext); mTrackers.remove(token); mPhone.notifySmsSent(tracker.mDestAddress); + mSmsDispatchersController.notifySmsSentToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); break; case ImsSmsImplBase.SEND_STATUS_ERROR: tracker.onFailed(mContext, reason, networkReasonCode); mTrackers.remove(token); + notifySmsSentFailedToEmergencyStateTracker(tracker); break; case ImsSmsImplBase.SEND_STATUS_ERROR_RETRY: int maxRetryCountOverIms = getMaxRetryCountOverIms(); @@ -222,6 +227,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { } else { tracker.onFailed(mContext, reason, networkReasonCode); mTrackers.remove(token); + notifySmsSentFailedToEmergencyStateTracker(tracker); } break; case ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK: @@ -242,6 +248,18 @@ public class ImsSmsDispatcher extends SMSDispatcher { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + true /* isOverIms */, + reason); + } + } + } + } finally { Binder.restoreCallingIdentity(identity); } @@ -642,6 +660,18 @@ public class ImsSmsDispatcher extends SMSDispatcher { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + true /* isOverIms */, + SmsManager.RESULT_SYSTEM_ERROR + ); + } + } + } } } diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index 91667199b3..eafb4ba038 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -71,6 +71,8 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.SmsConstants.MessageClass; +import com.android.internal.telephony.analytics.TelephonyAnalytics; +import com.android.internal.telephony.analytics.TelephonyAnalytics.SmsMmsAnalytics; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.telephony.util.TelephonyUtils; @@ -745,6 +747,16 @@ public abstract class InboundSmsHandler extends StateMachine { if (result != Intents.RESULT_SMS_HANDLED && result != Activity.RESULT_OK) { mMetrics.writeIncomingSmsError(mPhone.getPhoneId(), is3gpp2(), smsSource, result); mPhone.getSmsStats().onIncomingSmsError(is3gpp2(), smsSource, result); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onIncomingSmsError(smsSource, result); + } + } + } + } return result; } @@ -1008,6 +1020,16 @@ public abstract class InboundSmsHandler extends StateMachine { logeWithLocalLog(errorMsg, tracker.getMessageId()); mPhone.getSmsStats().onIncomingSmsError( is3gpp2(), tracker.getSource(), RESULT_SMS_NULL_PDU); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onIncomingSmsError( + tracker.getSource(), RESULT_SMS_NULL_PDU); + } + } + } return false; } @@ -1082,7 +1104,16 @@ public abstract class InboundSmsHandler extends StateMachine { format, timestamps, block, tracker.getMessageId()); mPhone.getSmsStats().onIncomingSmsSuccess(is3gpp2(), tracker.getSource(), messageCount, block, tracker.getMessageId()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onIncomingSmsSuccess(tracker.getSource()); + } + } + } // Always invoke SMS filters, even if the number ends up being blocked, to prevent // surprising bugs due to blocking numbers that happen to be used for visual voicemail SMS // or other carrier system messages. diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java index 0ee40bb6ff..3893c6a456 100644 --- a/src/java/com/android/internal/telephony/ModemIndication.java +++ b/src/java/com/android/internal/telephony/ModemIndication.java @@ -19,12 +19,14 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED; import android.hardware.radio.modem.IRadioModemIndication; +import android.hardware.radio.modem.ImeiInfo; import android.os.AsyncResult; import java.util.ArrayList; @@ -132,4 +134,18 @@ public class ModemIndication extends IRadioModemIndication.Stub { public int getInterfaceVersion() { return IRadioModemIndication.VERSION; } + + /** + * Indicates when there is a change in the IMEI with respect to the sim slot. + * + * @param imeiInfo IMEI information + */ + public void onImeiMappingChanged(int indicationType, ImeiInfo imeiInfo) { + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); + + if (mRil.isLogOrTrace()) { + mRil.unsljLogMore(RIL_UNSOL_IMEI_MAPPING_CHANGED, "ImeiMappingChanged"); + } + mRil.notifyRegistrantsImeiMappingChanged(imeiInfo); + } } diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index d6b09303be..d07e7312a3 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -541,7 +541,7 @@ public class MultiSimSettingController extends Handler { boolean setDefaultData = true; List<SubscriptionInfo> activeSubList = mSubscriptionManagerService .getActiveSubscriptionInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), true/*isForAllProfile*/); for (SubscriptionInfo activeInfo : activeSubList) { if (!(groupUuid.equals(activeInfo.getGroupUuid()))) { // Do not set refSubId as defaultDataSubId if there are other active @@ -588,7 +588,7 @@ public class MultiSimSettingController extends Handler { List<SubscriptionInfo> activeSubInfos = mSubscriptionManagerService .getActiveSubscriptionInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag()); + mContext.getAttributionTag(), true/*isForAllProfile*/); if (ArrayUtils.isEmpty(activeSubInfos)) { mPrimarySubList.clear(); diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 7f9ff798b3..d86c09090a 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -30,9 +30,11 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_REGISTRATION import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SECURITY_ALGORITHMS_UPDATED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELLULAR_IDENTIFIER_DISCLOSED; import android.annotation.ElapsedRealtimeLong; import android.hardware.radio.network.IRadioNetworkIndication; @@ -42,6 +44,7 @@ import android.telephony.AnomalyReporter; import android.telephony.BarringInfo; import android.telephony.CellIdentity; import android.telephony.CellInfo; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.EmergencyRegResult; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; @@ -128,7 +131,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { android.hardware.radio.network.LinkCapacityEstimate lce) { mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); - List<LinkCapacityEstimate> response = RILUtils.convertHalLceData(lce); + List<LinkCapacityEstimate> response = RILUtils.convertHalLinkCapacityEstimate(lce); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); @@ -168,7 +171,10 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { } if (band == PhysicalChannelConfig.BAND_UNKNOWN) { mRil.riljLoge("Unsupported unknown band."); - return; + // TODO, b/288310456, + // If the band is unknown, PhysicalChannelConfig can be built without setBand. + // It should be enforced not to allow "unknown" bands in the near future. + // return; } else { builder.setBand(band); } @@ -204,9 +210,8 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { android.hardware.radio.network.SignalStrength signalStrength) { mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); - SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength); + SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); - SignalStrength ss = mRil.fixupSignalStrength10(ssInitial); // Note this is set to "verbose" because it happens frequently if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); @@ -419,6 +424,40 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { new AsyncResult(null, response, null)); } + /** + * Cellular identifier disclosure events + * @param indicationType Type of radio indication + * @param identifierDisclsoure the result of the Emergency Network Scan + */ + public void cellularIdentifierDisclosed(int indicationType, + android.hardware.radio.network.CellularIdentifierDisclosure identifierDisclsoure) { + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); + + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CELLULAR_IDENTIFIER_DISCLOSED, identifierDisclsoure); + } + + CellularIdentifierDisclosure disclosure = + RILUtils.convertCellularIdentifierDisclosure(identifierDisclsoure); + + mRil.mCellularIdentifierDisclosedRegistrants.notifyRegistrants( + new AsyncResult(null, disclosure, null)); + } + + /** + * Security algorithm update events + * @param indicationType Type of radio indication + * @param securityAlgorithmUpdate details of what changed + */ + public void securityAlgorithmsUpdated(int indicationType, + android.hardware.radio.network.SecurityAlgorithmUpdate securityAlgorithmUpdate) { + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); + + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_SECURITY_ALGORITHMS_UPDATED, securityAlgorithmUpdate); + } + } + @Override public String getInterfaceHash() { return IRadioNetworkIndication.HASH; diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index b1eb9265ab..eb2cd16cca 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -25,12 +25,10 @@ import android.os.AsyncResult; import android.telephony.BarringInfo; import android.telephony.CellInfo; import android.telephony.EmergencyRegResult; -import android.telephony.LinkCapacityEstimate; import android.telephony.RadioAccessSpecifier; import android.telephony.SignalStrength; import java.util.ArrayList; -import java.util.List; /** * Interface declaring response functions to solicited radio requests for network APIs. @@ -269,23 +267,6 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { /** * @param responseInfo Response info struct containing response type, serial no. and error - * @param lceInfo LceDataInfo indicating LCE data - */ - public void pullLceDataResponse(RadioResponseInfo responseInfo, - android.hardware.radio.network.LceDataInfo lceInfo) { - RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); - - if (rr != null) { - List<LinkCapacityEstimate> ret = RILUtils.convertHalLceData(lceInfo); - if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - /** - * @param responseInfo Response info struct containing response type, serial no. and error */ public void setAllowedNetworkTypesBitmapResponse(RadioResponseInfo responseInfo) { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); @@ -523,6 +504,53 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setCellularIdentifierTransparencyEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param isEnabled Indicates whether cellular identifier disclosure transparency from the modem + * is enabled. + */ + public void isCellularIdentifierTransparencyEnabledResponse(RadioResponseInfo responseInfo, + boolean isEnabled) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, isEnabled); + } + mRil.processResponseDone(rr, responseInfo, isEnabled); + } + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setSecurityAlgorithmsUpdatedEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param isEnabled Indicates whether security algorithm updates from the modem are enabled. + */ + public void isSecurityAlgorithmsUpdatedEnabledResponse(RadioResponseInfo responseInfo, + boolean isEnabled) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, isEnabled); + } + mRil.processResponseDone(rr, responseInfo, isEnabled); + } + } + @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java index 75675669c1..c09f8fb91f 100644 --- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java +++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java @@ -42,7 +42,9 @@ import android.telephony.SubscriptionInfo; import android.telephony.TelephonyScanManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.subscription.SubscriptionManagerService; +import com.android.internal.util.ArrayUtils; import java.util.Collection; import java.util.List; @@ -131,7 +133,7 @@ public final class NetworkScanRequestTracker { } private boolean isValidScan(NetworkScanRequestInfo nsri) { - if (nsri.mRequest == null || nsri.mRequest.getSpecifiers() == null) { + if (nsri.mRequest == null || ArrayUtils.isEmpty(nsri.mRequest.getSpecifiers())) { return false; } if (nsri.mRequest.getSpecifiers().length > NetworkScanRequest.MAX_RADIO_ACCESS_NETWORKS) { @@ -251,9 +253,10 @@ public final class NetworkScanRequestTracker { /** * Tracks info about the radio network scan. * - * Also used to notice when the calling process dies so we can self-expire. + * Also used to notice when the calling process dies, so we can self-expire. */ - class NetworkScanRequestInfo implements IBinder.DeathRecipient { + @VisibleForTesting + public class NetworkScanRequestInfo implements IBinder.DeathRecipient { private final NetworkScanRequest mRequest; private final Messenger mMessenger; private final IBinder mBinder; @@ -265,8 +268,9 @@ public final class NetworkScanRequestTracker { private final String mCallingPackage; private boolean mIsBinderDead; - NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone, - int callingUid, int callingPid, String callingPackage, + @VisibleForTesting + public NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, + Phone phone, int callingUid, int callingPid, String callingPackage, boolean renounceFineLocationAccess) { super(); mRequest = r; @@ -445,6 +449,10 @@ public final class NetworkScanRequestTracker { Log.e(TAG, "EVENT_RECEIVE_NETWORK_SCAN_RESULT: nsri is null"); return; } + if (nsri != mLiveRequestInfo) { + Log.e(TAG, "EVENT_RECEIVE_NETWORK_SCAN_RESULT received for inactive scan"); + return; + } LocationAccessPolicy.LocationPermissionQuery locationQuery = new LocationAccessPolicy.LocationPermissionQuery.Builder() .setCallingPackage(nsri.mCallingPackage) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index d1c83590d3..e6fb84e1f4 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -594,9 +594,6 @@ public class NetworkTypeController extends StateMachine { log("Reset timers since physical channel config indications are off."); } resetAllTimers(); - mRatchetedNrBands.clear(); - mRatchetedNrBandwidths = 0; - mLastAnchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN; } transitionToCurrentState(); break; diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 0f4f528b72..d94473824e 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -72,7 +72,6 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; -import android.telephony.satellite.SatelliteDatagram; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; @@ -84,6 +83,7 @@ import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.analytics.TelephonyAnalytics; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; @@ -92,6 +92,7 @@ import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -219,7 +220,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private static final int EVENT_UNSOL_OEM_HOOK_RAW = 34; protected static final int EVENT_GET_RADIO_CAPABILITY = 35; protected static final int EVENT_SS = 36; - private static final int EVENT_CONFIG_LCE = 37; private static final int EVENT_CHECK_FOR_NETWORK_AUTOMATIC = 38; protected static final int EVENT_VOICE_RADIO_TECH_CHANGED = 39; protected static final int EVENT_REQUEST_VOICE_RADIO_TECH_DONE = 40; @@ -251,8 +251,12 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE = 66; protected static final int EVENT_GET_DEVICE_IMEI_DONE = 67; protected static final int EVENT_TRIGGER_NOTIFY_ANBR = 68; - - protected static final int EVENT_LAST = EVENT_TRIGGER_NOTIFY_ANBR; + protected static final int EVENT_GET_N1_MODE_ENABLED_DONE = 69; + protected static final int EVENT_SET_N1_MODE_ENABLED_DONE = 70; + protected static final int EVENT_IMEI_MAPPING_CHANGED = 71; + protected static final int EVENT_CELL_IDENTIFIER_DISCLOSURE = 72; + protected static final int EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE = 73; + protected static final int EVENT_LAST = EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE; // For shared prefs. private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_"; @@ -283,6 +287,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { "pref_null_cipher_and_integrity_enabled"; private final TelephonyAdminReceiver m2gAdminUpdater; + public static final String PREF_IDENTIFIER_DISCLOSURE_NOTIFICATIONS_ENABLED = + "pref_identifier_disclosure_notifications_enabled"; + + protected final FeatureFlags mFeatureFlags; + /** * This method is invoked when the Phone exits Emergency Callback Mode. */ @@ -371,9 +380,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private final AtomicReference<RadioCapability> mRadioCapability = new AtomicReference<RadioCapability>(); - private static final int DEFAULT_REPORT_INTERVAL_MS = 200; - private static final boolean LCE_PULL_MODE = true; - private int mLceStatus = RILConstants.LCE_NOT_AVAILABLE; protected TelephonyComponentFactory mTelephonyComponentFactory; private int mPreferredUsageSetting = SubscriptionManager.USAGE_SETTING_UNKNOWN; @@ -480,6 +486,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected VoiceCallSessionStats mVoiceCallSessionStats; protected SmsStats mSmsStats; + protected TelephonyAnalytics mTelephonyAnalytics; protected LinkBandwidthEstimator mLinkBandwidthEstimator; @@ -550,22 +557,25 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Constructs a Phone in normal (non-unit test) mode. * + * @param name a name for this phone object * @param notifier An instance of DefaultPhoneNotifier, * @param context Context object from hosting application * unless unit testing. * @param ci is CommandsInterface * @param unitTestMode when true, prevents notifications * of state change events + * @param featureFlags an instance of the FeatureFlags set */ protected Phone(String name, PhoneNotifier notifier, Context context, CommandsInterface ci, - boolean unitTestMode) { + boolean unitTestMode, FeatureFlags featureFlags) { this(name, notifier, context, ci, unitTestMode, SubscriptionManager.DEFAULT_PHONE_INDEX, - TelephonyComponentFactory.getInstance()); + TelephonyComponentFactory.getInstance(), featureFlags); } /** * Constructs a Phone in normal (non-unit test) mode. * + * @param name a name for this phone object * @param notifier An instance of DefaultPhoneNotifier, * @param context Context object from hosting application * unless unit testing. @@ -573,10 +583,13 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param unitTestMode when true, prevents notifications * of state change events * @param phoneId the phone-id of this phone. + * @param telephonyComponentFactory a factory for injecting telephony components + * @param featureFlags an instance of the FeatureFlags set */ protected Phone(String name, PhoneNotifier notifier, Context context, CommandsInterface ci, boolean unitTestMode, int phoneId, - TelephonyComponentFactory telephonyComponentFactory) { + TelephonyComponentFactory telephonyComponentFactory, + FeatureFlags featureFlags) { mPhoneId = phoneId; mName = name; mNotifier = notifier; @@ -589,6 +602,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { .makeAppSmsManager(context); mLocalLog = new LocalLog(64); + mFeatureFlags = featureFlags; + setUnitTestMode(unitTestMode); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); @@ -649,8 +664,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) { mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); } - mCi.startLceService(DEFAULT_REPORT_INTERVAL_MS, LCE_PULL_MODE, - obtainMessage(EVENT_CONFIG_LCE)); + //Initialize Telephony Analytics + if (mFeatureFlags.enableTelephonyAnalytics()) { + mTelephonyAnalytics = new TelephonyAnalytics(this); + } } /** @@ -830,16 +847,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // deprecated, ignore break; - case EVENT_CONFIG_LCE: - ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - Rlog.d(LOG_TAG, "config LCE service failed: " + ar.exception); - } else { - final ArrayList<Integer> statusInfo = (ArrayList<Integer>)ar.result; - mLceStatus = statusInfo.get(0); - } - break; - case EVENT_CHECK_FOR_NETWORK_AUTOMATIC: { onCheckForNetworkSelectionModeAutomatic(msg); break; @@ -889,7 +896,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } break; default: - throw new RuntimeException("unexpected event not handled"); + throw new RuntimeException("unexpected event not handled, msgId=" + msg.what); } } @@ -2743,47 +2750,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation. - * - * @param data The data for the request. - * @param response <strong>On success</strong>, - * (byte[])(((AsyncResult)response.obj).result) - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and - * (((AsyncResult)response.obj).exception) being an instance of - * com.android.internal.telephony.gsm.CommandException - * - * @see #invokeOemRilRequestRaw(byte[], android.os.Message) - * @deprecated OEM needs a vendor-extension hal and their apps should use that instead - */ - @UnsupportedAppUsage - @Deprecated - public void invokeOemRilRequestRaw(byte[] data, Message response) { - mCi.invokeOemRilRequestRaw(data, response); - } - - /** - * Invokes RIL_REQUEST_OEM_HOOK_Strings on RIL implementation. - * - * @param strings The strings to make available as the request data. - * @param response <strong>On success</strong>, "response" bytes is - * made available as: - * (String[])(((AsyncResult)response.obj).result). - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and - * (((AsyncResult)response.obj).exception) being an instance of - * com.android.internal.telephony.gsm.CommandException - * - * @see #invokeOemRilRequestStrings(java.lang.String[], android.os.Message) - * @deprecated OEM needs a vendor-extension hal and their apps should use that instead - */ - @UnsupportedAppUsage - @Deprecated - public void invokeOemRilRequestStrings(String[] strings, Message response) { - mCi.invokeOemRilRequestStrings(strings, response); - } - - /** * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}. * Used for device configuration by some CDMA operators. * @@ -4439,12 +4405,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { subInfo = subInfoInternal.toSubscriptionInfo(); } - if (subInfo == null - || subInfo.getUsageSetting() == SubscriptionManager.USAGE_SETTING_UNKNOWN) { + if (subInfo == null) { loge("Failed to get SubscriptionInfo for subId=" + subId); return SubscriptionManager.USAGE_SETTING_UNKNOWN; } + if (subInfo.getUsageSetting() == SubscriptionManager.USAGE_SETTING_UNKNOWN) { + return SubscriptionManager.USAGE_SETTING_UNKNOWN; + } + if (subInfo.getUsageSetting() != SubscriptionManager.USAGE_SETTING_DEFAULT) { return subInfo.getUsageSetting(); } @@ -4546,13 +4515,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Returns the status of Link Capacity Estimation (LCE) service. - */ - public int getLceStatus() { - return mLceStatus; - } - - /** * Returns the modem activity information */ public void getModemActivityInfo(Message response, WorkSource workSource) { @@ -4560,15 +4522,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Starts LCE service after radio becomes available. - * LCE service state may get destroyed on the modem when radio becomes unavailable. - */ - public void startLceAfterRadioIsAvailable() { - mCi.startLceService(DEFAULT_REPORT_INTERVAL_MS, LCE_PULL_MODE, - obtainMessage(EVENT_CONFIG_LCE)); - } - - /** * Control the data throttling at modem. * * @param result Message that will be sent back to the requester @@ -4827,6 +4780,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mSmsStats = smsStats; } + /** Getter for Telephony Analytics */ + public TelephonyAnalytics getTelephonyAnalytics() { + return mTelephonyAnalytics; + } + /** @hide */ public CarrierPrivilegesTracker getCarrierPrivilegesTracker() { return null; @@ -5195,6 +5153,28 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** + * @return whether or not this Phone interacts with a modem that supports the cellular + * identifier disclosure transparency feature. + */ + public boolean isIdentifierDisclosureTransparencySupported() { + return false; + } + + /** + * @return global cellular identifier disclosure transparency enabled preference + */ + public boolean getIdentifierDisclosureNotificationsPreferenceEnabled() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + return sp.getBoolean(PREF_IDENTIFIER_DISCLOSURE_NOTIFICATIONS_ENABLED, false); + } + + /** + * Override to handle an update to the cellular identifier disclosure transparency preference. + */ + public void handleIdentifierDisclosureNotificationPreferenceChange() { + } + + /** * Notifies the IMS call status to the modem. * * @param imsCallInfo The list of {@link ImsCallInfo}. @@ -5238,279 +5218,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Start receiving satellite position updates. - * This can be called by the pointing UI when the user starts pointing to the satellite. - * Modem should continue to report the pointing input as the device or satellite moves. - * - * @param result The Message to send to result of the operation to. - **/ - public void startSatellitePositionUpdates(Message result) { - mCi.startSendingSatellitePointingInfo(result); - } - - /** - * Stop receiving satellite position updates. - * This can be called by the pointing UI when the user stops pointing to the satellite. - * - * @param result The Message to send to result of the operation to. - **/ - public void stopSatellitePositionUpdates(Message result) { - mCi.stopSendingSatellitePointingInfo(result); - } - - /** - * Get maximum number of characters per text message on satellite. - * @param result The Message to send the result of the operation to. - */ - public void getMaxCharactersPerSatelliteTextMessage(Message result) { - mCi.getMaxCharactersPerSatelliteTextMessage(result); - } - - /** - * Power on or off the satellite modem. - * @param result The Message to send the result of the operation to. - * @param powerOn {@code true} to power on the satellite modem and {@code false} to power off. - */ - public void setSatellitePower(Message result, boolean powerOn) { - mCi.setSatellitePower(result, powerOn); - } - - /** - * Check whether the satellite modem is powered on. - * @param result The Message to send the result of the operation to. - */ - public void isSatellitePowerOn(Message result) { - mCi.getSatellitePowerState(result); - } - - /** - * Check whether the satellite service is supported on the device. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteSupported(Message result) { - mCi.isSatelliteSupported(result); - } - - /** - * Check whether the satellite modem is provisioned. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteProvisioned(Message result) { - mCi.getSatelliteProvisionState(result); - } - - /** - * Get the satellite capabilities. - * @param result The Message to send the result of the operation to. - */ - public void getSatelliteCapabilities(Message result) { - mCi.getSatelliteCapabilities(result); - } - - /** - * Registers for pointing info changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatellitePositionInfoChanged(@NonNull Handler h, - int what, @Nullable Object obj) { - //TODO: Rename CommandsInterface and other modules when updating HAL APIs. - mCi.registerForSatellitePointingInfoChanged(h, what, obj); - } - - /** - * Unregisters for pointing info changed from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) { - //TODO: Rename CommandsInterface and other modules when updating HAL APIs. - mCi.unregisterForSatellitePointingInfoChanged(h); - } - - /** - * Registers for datagrams delivered events from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatelliteDatagramsDelivered(@NonNull Handler h, - int what, @Nullable Object obj) { - //TODO: Remove. - mCi.registerForSatelliteMessagesTransferComplete(h, what, obj); - } - - /** - * Unregisters for datagrams delivered events from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - public void unregisterForSatelliteDatagramsDelivered(@NonNull Handler h) { - //TODO: Remove. - mCi.unregisterForSatelliteMessagesTransferComplete(h); - } - - /** - * Provision the subscription with a satellite provider. - * This is needed to register the device/subscription if the provider allows dynamic - * registration. - * - * @param result Callback message to receive the result. - * @param token The token of the device/subscription to be provisioned. - */ - public void provisionSatelliteService(Message result, String token) { - // TODO: update parameters in HAL - // mCi.provisionSatelliteService(result, token); - } - - /** - * Deprovision the device/subscription with a satellite provider. - * This is needed to unregister the device/subscription if the provider allows dynamic - * registration. - * If provisioning is in progress for the given SIM, cancel the request. - * If there is no request in progress, deprovision the given SIM. - * - * @param result Callback message to receive the result. - * @param token The token of the device/subscription to be deprovisioned. - */ - public void deprovisionSatelliteService(Message result, String token) { - //TODO (b/266126070): add implementation. - } - - /** - * Register for a satellite provision state changed event. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatelliteProvisionStateChanged(Handler h, int what, Object obj) { - mCi.registerForSatelliteProvisionStateChanged(h, what, obj); - } - - /** - * Unregister for a satellite provision state changed event. - * - * @param h Handler to be removed from the registrant list. - */ - public void unregisterForSatelliteProvisionStateChanged(Handler h) { - mCi.unregisterForSatelliteProvisionStateChanged(h); - } - - /** - * Get the list of provisioned satellite features. - * - * @param result Callback message to receive the result. - */ - public void getProvisionedSatelliteFeatures(Message result) { - //TODO (b/266126070): add implementation. - } - - /** - * Registers for satellite state changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatelliteModemStateChanged(@NonNull Handler h, int what, - @Nullable Object obj) { - mCi.registerForSatelliteModeChanged(h, what, obj); - } - - /** - * Unregisters for satellite state changed from satellite modem. - * - * @param h Handler to be removed from registrant list. - */ - public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) { - mCi.unregisterForSatelliteModeChanged(h); - } - - /** - * Registers for pending datagram count info from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForPendingDatagramCount(@NonNull Handler h, int what, - @Nullable Object obj) { - mCi.registerForPendingSatelliteMessageCount(h, what, obj); - } - - /** - * Unregisters for pending datagram count info from satellite modem. - * - * @param h Handler to be removed from registrant list. - */ - public void unregisterForPendingDatagramCount(@NonNull Handler h) { - mCi.unregisterForPendingSatelliteMessageCount(h); - } - - /** - * Register to receive incoming datagrams over satellite. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatelliteDatagramsReceived(@NonNull Handler h, int what, - @Nullable Object obj) { - // TODO: rename - mCi.registerForNewSatelliteMessages(h, what, obj); - } - - /** - * Unregister to stop receiving incoming datagrams over satellite. - * - * @param h Handler to be removed from registrant list. - */ - public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) { - // TODO: rename - mCi.unregisterForNewSatelliteMessages(h); - } - - /** - * Poll pending datagrams over satellite. - * @param result The Message to send the result of the operation to. - */ - public void pollPendingSatelliteDatagrams(Message result) { - //mCi.pollPendingSatelliteDatagrams(result); - } - - /** - * Send datagram over satellite. - * @param result The Message to send the result of the operation to. - * @param datagram Datagram to send over satellite. - * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in - * full screen mode. - */ - public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram, - boolean needFullScreenPointingUI) { - //mCi.sendSatelliteDatagram(result, datagram); - } - - /** - * Check whether satellite communication is allowed for the current location. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) { - mCi.isSatelliteCommunicationAllowedForCurrentLocation(result); - } - - /** - * Get the time after which the satellite will be visible. - * @param result The Message to send the result of the operation to. - */ - public void requestTimeForNextSatelliteVisibility(Message result) { - mCi.getTimeForNextSatelliteVisibility(result); - } - - /** * Start callback mode * @param type for callback mode entry. */ @@ -5727,6 +5434,13 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); } + if (mTelephonyAnalytics != null) { + try { + mTelephonyAnalytics.dump(fd, pw, args); + } catch (Exception e) { + e.printStackTrace(); + } + } } private void logd(String s) { diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index 06ab58448a..78d1387103 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static android.telephony.TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT; +import android.annotation.NonNull; import android.content.Context; import android.content.Intent; import android.os.AsyncResult; @@ -37,6 +38,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; @@ -75,6 +77,10 @@ public class PhoneConfigurationManager { private final Map<Integer, Boolean> mPhoneStatusMap; private MockableInterface mMi = new MockableInterface(); private TelephonyManager mTelephonyManager; + + /** Feature flags */ + @NonNull + private final FeatureFlags mFeatureFlags; /** * True if 'Virtual DSDA' i.e., in-call IMS connectivity on both subs with only single logical * modem, is enabled. @@ -88,10 +94,11 @@ public class PhoneConfigurationManager { * Init method to instantiate the object * Should only be called once. */ - public static PhoneConfigurationManager init(Context context) { + public static PhoneConfigurationManager init(Context context, + @NonNull FeatureFlags featureFlags) { synchronized (PhoneConfigurationManager.class) { if (sInstance == null) { - sInstance = new PhoneConfigurationManager(context); + sInstance = new PhoneConfigurationManager(context, featureFlags); } else { Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); } @@ -103,8 +110,9 @@ public class PhoneConfigurationManager { * Constructor. * @param context context needed to send broadcast. */ - private PhoneConfigurationManager(Context context) { + private PhoneConfigurationManager(Context context, @NonNull FeatureFlags featureFlags) { mContext = context; + mFeatureFlags = featureFlags; // TODO: send commands to modem once interface is ready. mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); //initialize with default, it'll get updated when RADIO is ON/AVAILABLE @@ -360,7 +368,7 @@ public class PhoneConfigurationManager { } private void notifyCapabilityChanged() { - PhoneNotifier notifier = new DefaultPhoneNotifier(mContext); + PhoneNotifier notifier = new DefaultPhoneNotifier(mContext, mFeatureFlags); notifier.notifyPhoneCapabilityChanged(mStaticCapability); } diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 57a375b9b4..d29eed1b2e 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -23,6 +23,7 @@ import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE; import static java.util.Arrays.copyOf; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -47,6 +48,8 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.data.TelephonyNetworkFactory; import com.android.internal.telephony.euicc.EuiccCardController; import com.android.internal.telephony.euicc.EuiccController; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.telephony.flags.FeatureFlagsImpl; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneFactory; import com.android.internal.telephony.metrics.MetricsCollector; @@ -59,6 +62,7 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -102,11 +106,17 @@ public class PhoneFactory { static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>(); private static MetricsCollector sMetricsCollector; private static RadioInterfaceCapabilityController sRadioHalCapabilities; + private static @NonNull FeatureFlags sFeatureFlags = new FeatureFlagsImpl(); //***** Class Methods - public static void makeDefaultPhones(Context context) { - makeDefaultPhone(context); + /** + * @param context The context. + * @param featureFlags The feature flag. + */ + public static void makeDefaultPhones(Context context, @NonNull FeatureFlags featureFlags) { + sFeatureFlags = featureFlags; + makeDefaultPhone(context, featureFlags); } /** @@ -114,7 +124,7 @@ public class PhoneFactory { * instances */ @UnsupportedAppUsage - public static void makeDefaultPhone(Context context) { + public static void makeDefaultPhone(Context context, @NonNull FeatureFlags featureFlags) { synchronized (sLockProxyPhones) { if (!sMadeDefaults) { sContext = context; @@ -151,9 +161,9 @@ public class PhoneFactory { } // register statsd pullers. - sMetricsCollector = new MetricsCollector(context); + sMetricsCollector = new MetricsCollector(context, sFeatureFlags); - sPhoneNotifier = new DefaultPhoneNotifier(context); + sPhoneNotifier = new DefaultPhoneNotifier(context, featureFlags); int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); @@ -198,7 +208,7 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); sSubscriptionManagerService = new SubscriptionManagerService(context, - Looper.myLooper()); + Looper.myLooper(), featureFlags); TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. getName()).initMultiSimSettingController(context); @@ -246,7 +256,7 @@ public class PhoneFactory { Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver."); } - sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext); + sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext, featureFlags); sCellularNetworkValidator = CellularNetworkValidator.make(sContext); @@ -255,7 +265,8 @@ public class PhoneFactory { sPhoneSwitcher = TelephonyComponentFactory.getInstance().inject( PhoneSwitcher.class.getName()). - makePhoneSwitcher(maxActivePhones, sContext, Looper.myLooper()); + makePhoneSwitcher(maxActivePhones, sContext, Looper.myLooper(), + featureFlags); sProxyController = ProxyController.getInstance(context); @@ -318,7 +329,7 @@ public class PhoneFactory { return injectedComponentFactory.makePhone(context, sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId, phoneType, - TelephonyComponentFactory.getInstance()); + TelephonyComponentFactory.getInstance(), sFeatureFlags); } @UnsupportedAppUsage @@ -446,7 +457,7 @@ public class PhoneFactory { * @return the {@code ImsPhone} object or null if the exception occured */ public static Phone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) { - return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone); + return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone, sFeatureFlags); } /** @@ -512,6 +523,27 @@ public class PhoneFactory { return sMetricsCollector; } + /** + * Print all feature flag configurations that Telephony is using for debugging purposes. + */ + private static void reflectAndPrintFlagConfigs(IndentingPrintWriter pw) { + + try { + // Look away, a forbidden technique (reflection) is being used to allow us to get + // all flag configs without having to add them manually to this method. + Method[] methods = FeatureFlags.class.getMethods(); + if (methods.length == 0) { + pw.println("NONE"); + return; + } + for (Method m : methods) { + pw.println(m.getName() + "-> " + m.invoke(sFeatureFlags)); + } + } catch (Exception e) { + pw.println("[ERROR]"); + } + } + public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " "); pw.println("PhoneFactory:"); @@ -604,8 +636,15 @@ public class PhoneFactory { } catch (Exception e) { e.printStackTrace(); } + pw.flush(); + pw.decreaseIndent(); + pw.println("++++++++++++++++++++++++++++++++"); + pw.println("Flag Configurations:"); + pw.increaseIndent(); + reflectAndPrintFlagConfigs(pw); pw.flush(); pw.decreaseIndent(); + pw.println("++++++++++++++++++++++++++++++++"); } } diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 5ecdfcbbd4..5177adb3b9 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -36,6 +36,7 @@ import android.hardware.radio.V1_0.RadioError; import android.hardware.radio.V1_0.RadioIndicationType; import android.hardware.radio.V1_0.RadioResponseInfo; import android.hardware.radio.V1_0.RadioResponseType; +import android.hardware.radio.modem.ImeiInfo; import android.net.KeepalivePacketData; import android.net.LinkProperties; import android.os.AsyncResult; @@ -58,13 +59,6 @@ import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.BarringInfo; import android.telephony.CarrierRestrictionRules; -import android.telephony.CellInfo; -import android.telephony.CellSignalStrengthCdma; -import android.telephony.CellSignalStrengthGsm; -import android.telephony.CellSignalStrengthLte; -import android.telephony.CellSignalStrengthNr; -import android.telephony.CellSignalStrengthTdscdma; -import android.telephony.CellSignalStrengthWcdma; import android.telephony.ClientRequestStats; import android.telephony.DomainSelectionService; import android.telephony.ImsiEncryptionInfo; @@ -73,8 +67,6 @@ import android.telephony.NeighboringCellInfo; import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessFamily; import android.telephony.RadioAccessSpecifier; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SignalThresholdInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyHistogram; @@ -104,6 +96,7 @@ import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubStat import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.SimPhonebookRecord; import com.android.internal.telephony.util.TelephonyUtils; +import com.android.internal.util.FunctionalUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -123,7 +116,6 @@ import java.util.concurrent.atomic.AtomicLong; /** * RIL implementation of the CommandsInterface. - * * {@hide} */ public class RIL extends BaseCommands implements CommandsInterface { @@ -136,8 +128,7 @@ public class RIL extends BaseCommands implements CommandsInterface { static final int RIL_HISTOGRAM_BUCKET_COUNT = 5; /** - * Wake lock timeout should be longer than the longest timeout in - * the vendor ril. + * Wake lock timeout should be longer than the longest timeout in the vendor ril. */ private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MS = 60000; @@ -159,18 +150,6 @@ public class RIL extends BaseCommands implements CommandsInterface { public static final HalVersion RADIO_HAL_VERSION_UNKNOWN = HalVersion.UNKNOWN; /** @hide */ - public static final HalVersion RADIO_HAL_VERSION_1_0 = new HalVersion(1, 0); - - /** @hide */ - public static final HalVersion RADIO_HAL_VERSION_1_1 = new HalVersion(1, 1); - - /** @hide */ - public static final HalVersion RADIO_HAL_VERSION_1_2 = new HalVersion(1, 2); - - /** @hide */ - public static final HalVersion RADIO_HAL_VERSION_1_3 = new HalVersion(1, 3); - - /** @hide */ public static final HalVersion RADIO_HAL_VERSION_1_4 = new HalVersion(1, 4); /** @hide */ @@ -185,8 +164,11 @@ public class RIL extends BaseCommands implements CommandsInterface { /** @hide */ public static final HalVersion RADIO_HAL_VERSION_2_1 = new HalVersion(2, 1); + /** @hide */ + public static final HalVersion RADIO_HAL_VERSION_2_2 = new HalVersion(2, 2); + // Hal version - private Map<Integer, HalVersion> mHalVersion = new HashMap<>(); + private final Map<Integer, HalVersion> mHalVersion = new HashMap<>(); //***** Instance Variables @@ -197,8 +179,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public final WakeLock mAckWakeLock; // Wake lock associated with ack sent final int mWakeLockTimeout; // Timeout associated with request/response final int mAckWakeLockTimeout; // Timeout associated with ack sent - // The number of wakelock requests currently active. Don't release the lock - // until dec'd to 0 + // The number of wakelock requests currently active. Don't release the lock until dec'd to 0. int mWakeLockCount; // Variables used to identify releasing of WL on wakelock timeouts @@ -331,11 +312,10 @@ public class RIL extends BaseCommands implements CommandsInterface { } if (RILJ_LOGD) { int count = mRequestList.size(); - Rlog.d(RILJ_LOG_TAG, "WAKE_LOCK_TIMEOUT " + - " mRequestList=" + count); + riljLog("WAKE_LOCK_TIMEOUT mRequestList=" + count); for (int i = 0; i < count; i++) { rr = mRequestList.valueAt(i); - Rlog.d(RILJ_LOG_TAG, i + ": [" + rr.mSerial + "] " + riljLog(i + ": [" + rr.mSerial + "] " + RILUtils.requestToString(rr.mRequest)); } } @@ -346,7 +326,7 @@ public class RIL extends BaseCommands implements CommandsInterface { case EVENT_ACK_WAKE_LOCK_TIMEOUT: if (msg.arg1 == mAckWlSequenceNum && clearWakeLock(FOR_ACK_WAKELOCK)) { if (RILJ_LOGV) { - Rlog.d(RILJ_LOG_TAG, "ACK_WAKE_LOCK_TIMEOUT"); + riljLog("ACK_WAKE_LOCK_TIMEOUT"); } } break; @@ -493,9 +473,9 @@ public class RIL extends BaseCommands implements CommandsInterface { clearRequestList(RADIO_NOT_AVAILABLE, false); if (service == HAL_SERVICE_RADIO) { - getRadioProxy(null); + getRadioProxy(); } else { - getRadioServiceProxy(service, null); + getRadioServiceProxy(service); } } @@ -605,10 +585,10 @@ public class RIL extends BaseCommands implements CommandsInterface { @VisibleForTesting public void setCompatVersion(int rilRequest, @NonNull HalVersion halVersion) { HalVersion oldVersion = getCompatVersion(rilRequest); - // Do not allow to set same or greater verions + // Do not allow to set same or greater versions if (oldVersion != null && halVersion.greaterOrEqual(oldVersion)) { - riljLoge("setCompatVersion with equal or greater one, ignored, halVerion=" + halVersion - + ", oldVerion=" + oldVersion); + riljLoge("setCompatVersion with equal or greater one, ignored, halVersion=" + halVersion + + ", oldVersion=" + oldVersion); return; } mCompatOverrides.put(rilRequest, halVersion); @@ -622,7 +602,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /** Returns a {@link IRadio} instance or null if the service is not available. */ @VisibleForTesting - public synchronized IRadio getRadioProxy(Message result) { + public synchronized IRadio getRadioProxy() { if (mHalVersion.containsKey(HAL_SERVICE_RADIO) && mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { return null; @@ -630,11 +610,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null; if (!mIsCellularSupported) { if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } return null; } @@ -673,39 +648,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } if (mRadioProxy == null) { - try { - mRadioProxy = android.hardware.radio.V1_3.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true); - mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_3); - } catch (NoSuchElementException e) { - } - } - - if (mRadioProxy == null) { - try { - mRadioProxy = android.hardware.radio.V1_2.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true); - mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_2); - } catch (NoSuchElementException e) { - } - } - - if (mRadioProxy == null) { - try { - mRadioProxy = android.hardware.radio.V1_1.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true); - mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_1); - } catch (NoSuchElementException e) { - } - } - - if (mRadioProxy == null) { - try { - mRadioProxy = android.hardware.radio.V1_0.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true); - mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_0); - } catch (NoSuchElementException e) { - } + riljLoge("IRadio <1.4 is no longer supported."); } if (mRadioProxy != null) { @@ -729,11 +672,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (mRadioProxy == null) { // getService() is a blocking call, so this should never happen riljLoge("getRadioProxy: mRadioProxy == null"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } } return mRadioProxy; @@ -745,28 +683,27 @@ public class RIL extends BaseCommands implements CommandsInterface { * {@link RadioImsProxy}, or null if the service is not available. */ @NonNull - public <T extends RadioServiceProxy> T getRadioServiceProxy(Class<T> serviceClass, - Message result) { + public <T extends RadioServiceProxy> T getRadioServiceProxy(Class<T> serviceClass) { if (serviceClass == RadioDataProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_DATA, result); + return (T) getRadioServiceProxy(HAL_SERVICE_DATA); } if (serviceClass == RadioMessagingProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_MESSAGING, result); + return (T) getRadioServiceProxy(HAL_SERVICE_MESSAGING); } if (serviceClass == RadioModemProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_MODEM, result); + return (T) getRadioServiceProxy(HAL_SERVICE_MODEM); } if (serviceClass == RadioNetworkProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_NETWORK, result); + return (T) getRadioServiceProxy(HAL_SERVICE_NETWORK); } if (serviceClass == RadioSimProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_SIM, result); + return (T) getRadioServiceProxy(HAL_SERVICE_SIM); } if (serviceClass == RadioVoiceProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_VOICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_VOICE); } if (serviceClass == RadioImsProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_IMS, result); + return (T) getRadioServiceProxy(HAL_SERVICE_IMS); } riljLoge("getRadioServiceProxy: unrecognized " + serviceClass); return null; @@ -778,18 +715,13 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @VisibleForTesting @NonNull - public synchronized RadioServiceProxy getRadioServiceProxy(int service, Message result) { + public synchronized RadioServiceProxy getRadioServiceProxy(int service) { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return mServiceProxies.get(service); if ((service >= HAL_SERVICE_IMS) && !isRadioServiceSupported(service)) { return mServiceProxies.get(service); } if (!mIsCellularSupported) { if (RILJ_LOGV) riljLog("getRadioServiceProxy: Not calling getService(): wifi-only"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } return mServiceProxies.get(service); } @@ -947,46 +879,7 @@ public class RIL extends BaseCommands implements CommandsInterface { if (serviceProxy.isEmpty() && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { - try { - mHalVersion.put(service, RADIO_HAL_VERSION_1_3); - serviceProxy.setHidl(mHalVersion.get(service), - android.hardware.radio.V1_3.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true)); - } catch (NoSuchElementException e) { - } - } - - if (serviceProxy.isEmpty() - && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { - try { - mHalVersion.put(service, RADIO_HAL_VERSION_1_2); - serviceProxy.setHidl(mHalVersion.get(service), - android.hardware.radio.V1_2.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true)); - } catch (NoSuchElementException e) { - } - } - - if (serviceProxy.isEmpty() - && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { - try { - mHalVersion.put(service, RADIO_HAL_VERSION_1_1); - serviceProxy.setHidl(mHalVersion.get(service), - android.hardware.radio.V1_1.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true)); - } catch (NoSuchElementException e) { - } - } - - if (serviceProxy.isEmpty() - && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { - try { - mHalVersion.put(service, RADIO_HAL_VERSION_1_0); - serviceProxy.setHidl(mHalVersion.get(service), - android.hardware.radio.V1_0.IRadio.getService( - HIDL_SERVICE_NAME[mPhoneId], true)); - } catch (NoSuchElementException e) { - } + riljLoge("IRadio <1.4 is no longer supported."); } if (!serviceProxy.isEmpty()) { @@ -1036,8 +929,7 @@ public class RIL extends BaseCommands implements CommandsInterface { break; } } else { - if (mHalVersion.get(service) - .greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(service).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { throw new AssertionError("serviceProxy shouldn't be HIDL with HAL 2.0"); } if (!mIsRadioProxyInitialized) { @@ -1063,11 +955,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (serviceProxy.isEmpty()) { // getService() is a blocking call, so this should never happen riljLoge("getRadioServiceProxy: serviceProxy == null"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } } return serviceProxy; @@ -1080,9 +967,9 @@ public class RIL extends BaseCommands implements CommandsInterface { if (active) { // Try to connect to RIL services and set response functions. if (service == HAL_SERVICE_RADIO) { - getRadioProxy(null); + getRadioProxy(); } else { - getRadioServiceProxy(service, null); + getRadioServiceProxy(service); } } else { resetProxyAndRequestList(service); @@ -1164,9 +1051,9 @@ public class RIL extends BaseCommands implements CommandsInterface { } } catch (SecurityException ex) { /* TODO(b/211920208): instead of the following workaround (guessing if - * we're in a test based on proxies being populated), mock ServiceManager - * to not throw SecurityException and return correct value based on what - * HAL we're testing. */ + * we're in a test based on proxies being populated), mock ServiceManager + * to not throw SecurityException and return correct value based on what + * HAL we're testing. */ if (proxies == null) throw ex; } mDeathRecipients.put(service, new BinderServiceDeathRecipient(service)); @@ -1211,11 +1098,11 @@ public class RIL extends BaseCommands implements CommandsInterface { // wakelock stuff is initialized above as callbacks are received on separate binder threads) for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { if (service == HAL_SERVICE_RADIO) { - getRadioProxy(null); + getRadioProxy(); } else { if (proxies == null) { // Prevent telephony tests from calling the service - getRadioServiceProxy(service, null); + getRadioServiceProxy(service); } } @@ -1292,7 +1179,8 @@ public class RIL extends BaseCommands implements CommandsInterface { private void addRequest(RILRequest rr) { acquireWakeLock(rr, FOR_WAKELOCK); Trace.asyncTraceForTrackBegin( - Trace.TRACE_TAG_NETWORK, "RIL", RILUtils.requestToString(rr.mRequest), rr.mSerial); + Trace.TRACE_TAG_NETWORK, "RIL", rr.mSerial + "> " + + RILUtils.requestToString(rr.mRequest), rr.mSerial); synchronized (mRequestList) { rr.mStartTimeMs = SystemClock.elapsedRealtime(); mRequestList.append(rr.mSerial, rr); @@ -1319,45 +1207,79 @@ public class RIL extends BaseCommands implements CommandsInterface { resetProxyAndRequestList(service); } - @Override - public void getIccCardStatus(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + private void radioServiceInvokeHelper(int service, RILRequest rr, String methodName, + FunctionalUtils.ThrowingRunnable helper) { + try { + helper.runOrThrow(); + } catch (RuntimeException e) { + riljLoge(methodName + " RuntimeException: " + e); + int error = RadioError.SYSTEM_ERR; + int responseType = RadioResponseType.SOLICITED; + processResponseInternal(service, rr.mSerial, error, responseType); + processResponseDoneInternal(rr, error, responseType, null); + } catch (Exception e) { + handleRadioProxyExceptionForRR(service, methodName, e); + } + } + + private boolean canMakeRequest(String request, RadioServiceProxy proxy, Message result, + HalVersion version) { + int service = HAL_SERVICE_RADIO; + if (proxy instanceof RadioDataProxy) { + service = HAL_SERVICE_DATA; + } else if (proxy instanceof RadioMessagingProxy) { + service = HAL_SERVICE_MESSAGING; + } else if (proxy instanceof RadioModemProxy) { + service = HAL_SERVICE_MODEM; + } else if (proxy instanceof RadioNetworkProxy) { + service = HAL_SERVICE_NETWORK; + } else if (proxy instanceof RadioSimProxy) { + service = HAL_SERVICE_SIM; + } else if (proxy instanceof RadioVoiceProxy) { + service = HAL_SERVICE_VOICE; + } else if (proxy instanceof RadioImsProxy) { + service = HAL_SERVICE_IMS; + } + + if (mHalVersion.get(service).less(version)) { + riljLoge(String.format("%s not supported on service %s < %s.", + request, serviceToString(service), version)); + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } - - try { - simProxy.getIccCardStatus(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getIccCardStatus", e); + return false; + } + if (proxy == null || proxy.isEmpty()) { + riljLoge(String.format("Unable to complete %s because service %s is not available.", + request, serviceToString(service))); + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); + result.sendToTarget(); } + return false; } + return true; } @Override - public void getIccSlotsStatus(Message result) { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getIccSlotsStatus: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + public void getIccCardStatus(Message result) { + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getIccCardStatus", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; } - } - @Override - public void setLogicalToPhysicalSlotMapping(int[] physicalSlots, Message result) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result, mRILDefaultWorkSource); + if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setLogicalToPhysicalSlotMapping: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getIccCardStatus", () -> { + simProxy.getIccCardStatus(rr.mSerial); + }); } @Override @@ -1367,22 +1289,22 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void supplyIccPinForApp(String pin, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN, result, mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("supplyIccPinForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN, result, mRILDefaultWorkSource); - try { - simProxy.supplyIccPinForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPinForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "supplyIccPinForApp", () -> { + simProxy.supplyIccPinForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override @@ -1392,24 +1314,24 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK, result, mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("supplyIccPukForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - String pukStr = RILUtils.convertNullToEmptyString(puk); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " isPukEmpty = " + pukStr.isEmpty() + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK, result, mRILDefaultWorkSource); - try { - simProxy.supplyIccPukForApp(rr.mSerial, pukStr, - RILUtils.convertNullToEmptyString(newPin), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPukForApp", e); - } + String pukStr = RILUtils.convertNullToEmptyString(puk); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " isPukEmpty = " + pukStr.isEmpty() + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "supplyIccPukForApp", () -> { + simProxy.supplyIccPukForApp(rr.mSerial, pukStr, + RILUtils.convertNullToEmptyString(newPin), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override @@ -1419,23 +1341,22 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void supplyIccPin2ForApp(String pin, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN2, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("supplyIccPin2ForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN2, result, mRILDefaultWorkSource); - try { - simProxy.supplyIccPin2ForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPin2ForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "supplyIccPin2ForApp", () -> { + simProxy.supplyIccPin2ForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override @@ -1445,24 +1366,23 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void supplyIccPuk2ForApp(String puk, String newPin2, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK2, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("supplyIccPuk2ForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK2, result, mRILDefaultWorkSource); - try { - simProxy.supplyIccPuk2ForApp(rr.mSerial, RILUtils.convertNullToEmptyString(puk), - RILUtils.convertNullToEmptyString(newPin2), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPuk2ForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "supplyIccPuk2ForApp", () -> { + simProxy.supplyIccPuk2ForApp(rr.mSerial, RILUtils.convertNullToEmptyString(puk), + RILUtils.convertNullToEmptyString(newPin2), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override @@ -1472,25 +1392,24 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void changeIccPinForApp(String oldPin, String newPin, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("changeIccPinForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " oldPin = " + oldPin + " newPin = " + newPin + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN, result, mRILDefaultWorkSource); - try { - simProxy.changeIccPinForApp(rr.mSerial, - RILUtils.convertNullToEmptyString(oldPin), - RILUtils.convertNullToEmptyString(newPin), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "changeIccPinForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " oldPin = " + oldPin + " newPin = " + newPin + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "changeIccPinForApp", () -> { + simProxy.changeIccPinForApp(rr.mSerial, + RILUtils.convertNullToEmptyString(oldPin), + RILUtils.convertNullToEmptyString(newPin), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override @@ -1500,102 +1419,92 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void changeIccPin2ForApp(String oldPin2, String newPin2, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN2, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("changeIccPin2ForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " oldPin = " + oldPin2 + " newPin = " + newPin2 + " aid = " + aid); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN2, result, mRILDefaultWorkSource); - try { - simProxy.changeIccPin2ForApp(rr.mSerial, - RILUtils.convertNullToEmptyString(oldPin2), - RILUtils.convertNullToEmptyString(newPin2), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "changeIccPin2ForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " oldPin = " + oldPin2 + " newPin = " + newPin2 + " aid = " + aid); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "changeIccPin2ForApp", () -> { + simProxy.changeIccPin2ForApp(rr.mSerial, + RILUtils.convertNullToEmptyString(oldPin2), + RILUtils.convertNullToEmptyString(newPin2), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override public void supplyNetworkDepersonalization(String netpin, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("supplyNetworkDepersonalization", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " netpin = " + netpin); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result, + mRILDefaultWorkSource); - try { - networkProxy.supplyNetworkDepersonalization(rr.mSerial, - RILUtils.convertNullToEmptyString(netpin)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_NETWORK, "supplyNetworkDepersonalization", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " netpin = " + netpin); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "supplyNetworkDepersonalization", () -> { + networkProxy.supplyNetworkDepersonalization(rr.mSerial, + RILUtils.convertNullToEmptyString(netpin)); + }); } @Override public void supplySimDepersonalization(PersoSubState persoType, String controlKey, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, result, - mRILDefaultWorkSource); + if (mHalVersion.get(HAL_SERVICE_SIM).less(RADIO_HAL_VERSION_1_5) + && PersoSubState.PERSOSUBSTATE_SIM_NETWORK == persoType) { + supplyNetworkDepersonalization(controlKey, result); + return; + } + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("supplySimDepersonalization", simProxy, result, + RADIO_HAL_VERSION_1_5)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " controlKey = " + controlKey + " persoType" + persoType); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, result, + mRILDefaultWorkSource); - try { - simProxy.supplySimDepersonalization(rr.mSerial, persoType, - RILUtils.convertNullToEmptyString(controlKey)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplySimDepersonalization", e); - } - } else { - if (PersoSubState.PERSOSUBSTATE_SIM_NETWORK == persoType) { - supplyNetworkDepersonalization(controlKey, result); - return; - } - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "supplySimDepersonalization: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " controlKey = " + controlKey + " persoType" + persoType); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "supplySimDepersonalization", () -> { + simProxy.supplySimDepersonalization(rr.mSerial, persoType, + RILUtils.convertNullToEmptyString(controlKey)); + }); } @Override public void getCurrentCalls(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("getCurrentCalls", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result, mRILDefaultWorkSource); - try { - voiceProxy.getCurrentCalls(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCurrentCalls", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "getCurrentCalls", () -> { + voiceProxy.getCurrentCalls(rr.mSerial); + }); } @Override @@ -1607,167 +1516,127 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void enableModem(boolean enable, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (modemProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_MODEM, result, mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("enableModem", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_MODEM, result, mRILDefaultWorkSource); - try { - modemProxy.enableModem(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, - "enableModem", e); - } - } else { - if (RILJ_LOGV) riljLog("enableModem: not supported."); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "enableModem", () -> { + modemProxy.enableModem(rr.mSerial, enable); + }); } @Override public void setSystemSelectionChannels(@NonNull List<RadioAccessSpecifier> specifiers, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setSystemSelectionChannels", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " setSystemSelectionChannels_1.3= " + specifiers); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, result, + mRILDefaultWorkSource); - try { - networkProxy.setSystemSelectionChannels(rr.mSerial, specifiers); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "setSystemSelectionChannels", e); - } - } else { - if (RILJ_LOGV) riljLog("setSystemSelectionChannels: not supported."); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " setSystemSelectionChannels= " + specifiers); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setSystemSelectionChannels", () -> { + networkProxy.setSystemSelectionChannels(rr.mSerial, specifiers); + }); } @Override public void getSystemSelectionChannels(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getSystemSelectionChannels", networkProxy, result, + RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " getSystemSelectionChannels"); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS, result, + mRILDefaultWorkSource); - try { - networkProxy.getSystemSelectionChannels(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "getSystemSelectionChannels", e); - } - } else { - if (RILJ_LOGV) riljLog("getSystemSelectionChannels: not supported."); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " getSystemSelectionChannels"); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getSystemSelectionChannels", () -> { + networkProxy.getSystemSelectionChannels(rr.mSerial); + }); } @Override public void getModemStatus(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (modemProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_MODEM_STATUS, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getModemStatus", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_MODEM_STATUS, result, mRILDefaultWorkSource); - try { - modemProxy.getModemStackStatus(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getModemStatus", e); - } - } else { - if (RILJ_LOGV) riljLog("getModemStatus: not supported."); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getModemStatus", () -> { + modemProxy.getModemStackStatus(rr.mSerial); + }); } @Override public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo, boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result) { - if (isEmergencyCall - && mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_1_4) - && emergencyNumberInfo != null) { + if (isEmergencyCall && emergencyNumberInfo != null) { emergencyDial(address, emergencyNumberInfo, hasKnownUserIntentEmergency, clirMode, uusInfo, result); return; } - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("dial", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result, mRILDefaultWorkSource); - try { - voiceProxy.dial(rr.mSerial, address, clirMode, uusInfo); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "dial", e); - } + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "dial", () -> { + voiceProxy.dial(rr.mSerial, address, clirMode, uusInfo); + }); } private void emergencyDial(String address, EmergencyNumber emergencyNumberInfo, boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (voiceProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_1_4)) { - RILRequest rr = obtainRequest(RIL_REQUEST_EMERGENCY_DIAL, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("emergencyDial", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_EMERGENCY_DIAL, result, mRILDefaultWorkSource); - try { - voiceProxy.emergencyDial(rr.mSerial, RILUtils.convertNullToEmptyString(address), - emergencyNumberInfo, hasKnownUserIntentEmergency, clirMode, uusInfo); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "emergencyDial", e); - } - } else { - riljLoge("emergencyDial is not supported with 1.4 below IRadio"); + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "emergencyDial", () -> { + voiceProxy.emergencyDial(rr.mSerial, RILUtils.convertNullToEmptyString(address), + emergencyNumberInfo, hasKnownUserIntentEmergency, clirMode, uusInfo); + }); } @Override @@ -1777,304 +1646,305 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void getIMSIForApp(String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result, mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getIMSIForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " aid = " + aid); - } - try { - simProxy.getImsiForApp(rr.mSerial, RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getImsiForApp", e); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result, mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " aid = " + aid); } + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getIMSIForApp", () -> { + simProxy.getImsiForApp(rr.mSerial, RILUtils.convertNullToEmptyString(aid)); + }); } @Override public void hangupConnection(int gsmIndex, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("hangupConnection", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " gsmIndex = " + gsmIndex); - } + RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP, result, mRILDefaultWorkSource); - try { - voiceProxy.hangup(rr.mSerial, gsmIndex); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "hangup", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " gsmIndex = " + gsmIndex); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "hangupConnection", () -> { + voiceProxy.hangup(rr.mSerial, gsmIndex); + }); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override public void hangupWaitingOrBackground(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("hangupWaitingOrBackground", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result, + mRILDefaultWorkSource); - try { - voiceProxy.hangupWaitingOrBackground(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "hangupWaitingOrBackground", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "hangupWaitingOrBackground", () -> { + voiceProxy.hangupWaitingOrBackground(rr.mSerial); + }); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override public void hangupForegroundResumeBackground(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("hangupForegroundResumeBackground", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result, + mRILDefaultWorkSource); - try { - voiceProxy.hangupForegroundResumeBackground(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_VOICE, "hangupForegroundResumeBackground", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "hangupForegroundResumeBackground", () -> { + voiceProxy.hangupForegroundResumeBackground(rr.mSerial); + }); } @Override public void switchWaitingOrHoldingAndActive(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("switchWaitingOrHoldingAndActive", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result, + mRILDefaultWorkSource); - try { - voiceProxy.switchWaitingOrHoldingAndActive(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, - "switchWaitingOrHoldingAndActive", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "switchWaitingOrHoldingAndActive", () -> { + voiceProxy.switchWaitingOrHoldingAndActive(rr.mSerial); + }); } @Override public void conference(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CONFERENCE, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("conference", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CONFERENCE, result, mRILDefaultWorkSource); - try { - voiceProxy.conference(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "conference", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "conference", () -> { + voiceProxy.conference(rr.mSerial); + }); } @Override public void rejectCall(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_UDUB, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("rejectCall", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_UDUB, result, mRILDefaultWorkSource); - try { - voiceProxy.rejectCall(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "rejectCall", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "rejectCall", () -> { + voiceProxy.rejectCall(rr.mSerial); + }); } @Override public void getLastCallFailCause(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("getLastCallFailCause", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result, + mRILDefaultWorkSource); - try { - voiceProxy.getLastCallFailCause(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getLastCallFailCause", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "getLastCallFailCause", () -> { + voiceProxy.getLastCallFailCause(rr.mSerial); + }); } @Override public void getSignalStrength(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIGNAL_STRENGTH, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getSignalStrength", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIGNAL_STRENGTH, result, mRILDefaultWorkSource); - try { - networkProxy.getSignalStrength(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getSignalStrength", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getSignalStrength", () -> { + networkProxy.getSignalStrength(rr.mSerial); + }); } @Override public void getVoiceRegistrationState(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_REGISTRATION_STATE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getVoiceRegistrationState", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_REGISTRATION_STATE, result, + mRILDefaultWorkSource); - HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_VOICE_REGISTRATION_STATE); - if (RILJ_LOGD) { - riljLog("getVoiceRegistrationState: overrideHalVersion=" + overrideHalVersion); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } - try { - networkProxy.getVoiceRegistrationState(rr.mSerial, overrideHalVersion); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getVoiceRegistrationState", e); - } + HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_VOICE_REGISTRATION_STATE); + if (RILJ_LOGD) { + riljLog("getVoiceRegistrationState: overrideHalVersion=" + overrideHalVersion); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getVoiceRegistrationState", () -> { + networkProxy.getVoiceRegistrationState(rr.mSerial, overrideHalVersion); + }); } @Override public void getDataRegistrationState(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DATA_REGISTRATION_STATE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getDataRegistrationState", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DATA_REGISTRATION_STATE, result, + mRILDefaultWorkSource); - HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_DATA_REGISTRATION_STATE); - if (RILJ_LOGD) { - riljLog("getDataRegistrationState: overrideHalVersion=" + overrideHalVersion); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } - try { - networkProxy.getDataRegistrationState(rr.mSerial, overrideHalVersion); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getDataRegistrationState", e); - } + HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_DATA_REGISTRATION_STATE); + if (RILJ_LOGD) { + riljLog("getDataRegistrationState: overrideHalVersion=" + overrideHalVersion); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getDataRegistrationState", () -> { + networkProxy.getDataRegistrationState(rr.mSerial, overrideHalVersion); + }); } @Override public void getOperator(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_OPERATOR, result, mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getOperator", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_OPERATOR, result, mRILDefaultWorkSource); - try { - networkProxy.getOperator(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getOperator", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getOperator", () -> { + networkProxy.getOperator(rr.mSerial); + }); } @UnsupportedAppUsage @Override public void setRadioPower(boolean on, boolean forEmergencyCall, boolean preferredForEmergencyCall, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_RADIO_POWER, result, mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("setRadioPower", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " on = " + on + " forEmergencyCall= " + forEmergencyCall - + " preferredForEmergencyCall=" + preferredForEmergencyCall); - } + RILRequest rr = obtainRequest(RIL_REQUEST_RADIO_POWER, result, mRILDefaultWorkSource); - try { - modemProxy.setRadioPower(rr.mSerial, on, forEmergencyCall, - preferredForEmergencyCall); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "setRadioPower", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " on = " + on + " forEmergencyCall= " + forEmergencyCall + + " preferredForEmergencyCall=" + preferredForEmergencyCall); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "setRadioPower", () -> { + modemProxy.setRadioPower(rr.mSerial, on, forEmergencyCall, + preferredForEmergencyCall); + }); } @Override public void sendDtmf(char c, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DTMF, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("sendDtmf", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DTMF, result, mRILDefaultWorkSource); - try { - voiceProxy.sendDtmf(rr.mSerial, c + ""); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendDtmf", e); - } + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "sendDtmf", () -> { + voiceProxy.sendDtmf(rr.mSerial, c + ""); + }); } @Override public void sendSMS(String smscPdu, String pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEND_SMS, result, mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendSMS", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_SMS, result, mRILDefaultWorkSource); - try { - messagingProxy.sendSms(rr.mSerial, smscPdu, pdu); - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, - SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendSMS", e); - } + // Do not log function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendSMS", () -> { + messagingProxy.sendSms(rr.mSerial, smscPdu, pdu); + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, + SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); + }); } /** @@ -2097,69 +1967,52 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void sendSMSExpectMore(String smscPdu, String pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEND_SMS_EXPECT_MORE, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendSMSExpectMore", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function arg for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_SMS_EXPECT_MORE, result, + mRILDefaultWorkSource); - try { - messagingProxy.sendSmsExpectMore(rr.mSerial, smscPdu, pdu); - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, - SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendSMSExpectMore", e); - } + // Do not log function arg for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendSMSExpectMore", () -> { + messagingProxy.sendSmsExpectMore(rr.mSerial, smscPdu, pdu); + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, + SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); + }); } @Override - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SETUP_DATA_CALL, result, - mRILDefaultWorkSource); + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean allowRoaming, + int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, Message result) { + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("setupDataCall", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + ",reason=" + RILUtils.setupDataReasonToString(reason) - + ",accessNetworkType=" + AccessNetworkType.toString(accessNetworkType) - + ",dataProfile=" + dataProfile + ",isRoaming=" + isRoaming - + ",allowRoaming=" + allowRoaming - + ",linkProperties=" + linkProperties + ",pduSessionId=" + pduSessionId - + ",sliceInfo=" + sliceInfo + ",trafficDescriptor=" + trafficDescriptor - + ",matchAllRuleAllowed=" + matchAllRuleAllowed); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SETUP_DATA_CALL, result, mRILDefaultWorkSource); - try { - dataProxy.setupDataCall(rr.mSerial, mPhoneId, accessNetworkType, dataProfile, - isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, - trafficDescriptor, matchAllRuleAllowed); - } catch (RemoteException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setupDataCall", e); - } catch (RuntimeException e) { - riljLoge("setupDataCall RuntimeException: " + e); - int error = RadioError.SYSTEM_ERR; - int responseType = RadioResponseType.SOLICITED; - processResponseInternal(HAL_SERVICE_DATA, rr.mSerial, error, responseType); - processResponseDoneInternal(rr, error, responseType, null); - } - } else { - riljLoge("setupDataCall: DataProxy is empty"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + ",reason=" + RILUtils.setupDataReasonToString(reason) + + ",accessNetworkType=" + AccessNetworkType.toString(accessNetworkType) + + ",dataProfile=" + dataProfile + ",allowRoaming=" + allowRoaming + + ",linkProperties=" + linkProperties + ",pduSessionId=" + pduSessionId + + ",sliceInfo=" + sliceInfo + ",trafficDescriptor=" + trafficDescriptor + + ",matchAllRuleAllowed=" + matchAllRuleAllowed); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "setupDataCall", () -> { + dataProxy.setupDataCall(rr.mSerial, accessNetworkType, dataProfile, allowRoaming, + reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor, + matchAllRuleAllowed); + }); } @Override @@ -2171,257 +2024,251 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void iccIOForApp(int command, int fileId, String path, int p1, int p2, int p3, String data, String pin2, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_IO, result, mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("iccIOForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - if (TelephonyUtils.IS_DEBUGGABLE) { - riljLog(rr.serialString() + "> iccIO: " + RILUtils.requestToString(rr.mRequest) - + " command = 0x" + Integer.toHexString(command) + " fileId = 0x" - + Integer.toHexString(fileId) + " path = " + path + " p1 = " + p1 - + " p2 = " + p2 + " p3 = " + " data = " + data + " aid = " + aid); - } else { - riljLog(rr.serialString() + "> iccIO: " - + RILUtils.requestToString(rr.mRequest)); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_IO, result, mRILDefaultWorkSource); - try { - simProxy.iccIoForApp(rr.mSerial, command, fileId, - RILUtils.convertNullToEmptyString(path), p1, p2, p3, - RILUtils.convertNullToEmptyString(data), - RILUtils.convertNullToEmptyString(pin2), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccIoForApp", e); + if (RILJ_LOGD) { + if (TelephonyUtils.IS_DEBUGGABLE) { + riljLog(rr.serialString() + "> iccIO: " + RILUtils.requestToString(rr.mRequest) + + " command = 0x" + Integer.toHexString(command) + " fileId = 0x" + + Integer.toHexString(fileId) + " path = " + path + " p1 = " + p1 + + " p2 = " + p2 + " p3 = " + " data = " + data + " aid = " + aid); + } else { + riljLog(rr.serialString() + "> iccIO: " + + RILUtils.requestToString(rr.mRequest)); } } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "iccIOForApp", () -> { + simProxy.iccIoForApp(rr.mSerial, command, fileId, + RILUtils.convertNullToEmptyString(path), p1, p2, p3, + RILUtils.convertNullToEmptyString(data), + RILUtils.convertNullToEmptyString(pin2), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override public void sendUSSD(String ussd, Message result) { - RadioVoiceProxy voiceProxy = - getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEND_USSD, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("sendUSSD", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - String logUssd = "*******"; - if (RILJ_LOGV) logUssd = ussd; - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " ussd = " + logUssd); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_USSD, result, mRILDefaultWorkSource); - try { - voiceProxy.sendUssd(rr.mSerial, RILUtils.convertNullToEmptyString(ussd)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendUssd", e); - } + if (RILJ_LOGD) { + String logUssd = "*******"; + if (RILJ_LOGV) logUssd = ussd; + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " ussd = " + logUssd); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "sendUSSD", () -> { + voiceProxy.sendUssd(rr.mSerial, RILUtils.convertNullToEmptyString(ussd)); + }); } @Override public void cancelPendingUssd(Message result) { - RadioVoiceProxy voiceProxy = - getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_USSD, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("cancelPendingUssd", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_USSD, result, mRILDefaultWorkSource); - try { - voiceProxy.cancelPendingUssd(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "cancelPendingUssd", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "cancelPendingUssd", () -> { + voiceProxy.cancelPendingUssd(rr.mSerial); + }); } @Override public void getCLIR(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_CLIR, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("getCLIR", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_CLIR, result, mRILDefaultWorkSource); - try { - voiceProxy.getClir(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getClir", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "getCLIR", () -> { + voiceProxy.getClir(rr.mSerial); + }); } @Override public void setCLIR(int clirMode, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_CLIR, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setCLIR", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " clirMode = " + clirMode); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_CLIR, result, mRILDefaultWorkSource); - try { - voiceProxy.setClir(rr.mSerial, clirMode); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setClir", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " clirMode = " + clirMode); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setCLIR", () -> { + voiceProxy.setClir(rr.mSerial, clirMode); + }); } @Override public void queryCallForwardStatus(int cfReason, int serviceClass, String number, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("queryCallForwardStatus", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " cfreason = " + cfReason + " serviceClass = " + serviceClass); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, result, + mRILDefaultWorkSource); - try { - voiceProxy.getCallForwardStatus(rr.mSerial, cfReason, serviceClass, number); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCallForwardStatus", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " cfReason = " + cfReason + " serviceClass = " + serviceClass); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "queryCallForwardStatus", () -> { + voiceProxy.getCallForwardStatus(rr.mSerial, cfReason, serviceClass, number); + }); } @Override public void setCallForward(int action, int cfReason, int serviceClass, String number, int timeSeconds, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_CALL_FORWARD, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setCallForward", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " action = " + action + " cfReason = " + cfReason + " serviceClass = " - + serviceClass + " timeSeconds = " + timeSeconds); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_CALL_FORWARD, result, mRILDefaultWorkSource); - try { - voiceProxy.setCallForward( - rr.mSerial, action, cfReason, serviceClass, number, timeSeconds); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setCallForward", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " action = " + action + " cfReason = " + cfReason + " serviceClass = " + + serviceClass + " timeSeconds = " + timeSeconds); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setCallForward", () -> { + voiceProxy.setCallForward( + rr.mSerial, action, cfReason, serviceClass, number, timeSeconds); + }); } @Override public void queryCallWaiting(int serviceClass, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CALL_WAITING, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("queryCallWaiting", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " serviceClass = " + serviceClass); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CALL_WAITING, result, + mRILDefaultWorkSource); - try { - voiceProxy.getCallWaiting(rr.mSerial, serviceClass); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCallWaiting", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " serviceClass = " + serviceClass); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "queryCallWaiting", () -> { + voiceProxy.getCallWaiting(rr.mSerial, serviceClass); + }); } @Override public void setCallWaiting(boolean enable, int serviceClass, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_CALL_WAITING, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setCallWaiting", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + enable + " serviceClass = " + serviceClass); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_CALL_WAITING, result, mRILDefaultWorkSource); - try { - voiceProxy.setCallWaiting(rr.mSerial, enable, serviceClass); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setCallWaiting", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + enable + " serviceClass = " + serviceClass); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setCallWaiting", () -> { + voiceProxy.setCallWaiting(rr.mSerial, enable, serviceClass); + }); } @Override public void acknowledgeLastIncomingGsmSms(boolean success, int cause, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SMS_ACKNOWLEDGE, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("acknowledgeLastIncomingGsmSms", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " success = " + success + " cause = " + cause); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SMS_ACKNOWLEDGE, result, mRILDefaultWorkSource); - try { - messagingProxy.acknowledgeLastIncomingGsmSms(rr.mSerial, success, cause); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, - "acknowledgeLastIncomingGsmSms", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " success = " + success + " cause = " + cause); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "acknowledgeLastIncomingGsmSms", () -> { + messagingProxy.acknowledgeLastIncomingGsmSms(rr.mSerial, success, cause); + }); } @Override public void acceptCall(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ANSWER, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("acceptCall", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ANSWER, result, mRILDefaultWorkSource); - try { - voiceProxy.acceptCall(rr.mSerial); - mMetrics.writeRilAnswer(mPhoneId, rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "acceptCall", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "acceptCall", () -> { + voiceProxy.acceptCall(rr.mSerial); + mMetrics.writeRilAnswer(mPhoneId, rr.mSerial); + }); } @Override public void deactivateDataCall(int cid, int reason, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, result, - mRILDefaultWorkSource); + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("deactivateDataCall", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " cid = " + cid + " reason = " - + RILUtils.deactivateDataReasonToString(reason)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, result, + mRILDefaultWorkSource); - try { - dataProxy.deactivateDataCall(rr.mSerial, cid, reason); - mMetrics.writeRilDeactivateDataCall(mPhoneId, rr.mSerial, cid, reason); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "deactivateDataCall", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " cid = " + cid + " reason = " + + RILUtils.deactivateDataReasonToString(reason)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "deactivateDataCall", () -> { + dataProxy.deactivateDataCall(rr.mSerial, cid, reason); + mMetrics.writeRilDeactivateDataCall(mPhoneId, rr.mSerial, cid, reason); + }); } @Override @@ -2433,26 +2280,27 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void queryFacilityLockForApp(String facility, String password, int serviceClass, String appId, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_FACILITY_LOCK, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("queryFacilityLockForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " facility = " + facility + " serviceClass = " + serviceClass - + " appId = " + appId); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_FACILITY_LOCK, result, + mRILDefaultWorkSource); - try { - simProxy.getFacilityLockForApp(rr.mSerial, - RILUtils.convertNullToEmptyString(facility), - RILUtils.convertNullToEmptyString(password), - serviceClass, RILUtils.convertNullToEmptyString(appId)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getFacilityLockForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " facility = " + facility + " serviceClass = " + serviceClass + + " appId = " + appId); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "queryFacilityLockForApp", () -> { + simProxy.getFacilityLockForApp(rr.mSerial, + RILUtils.convertNullToEmptyString(facility), + RILUtils.convertNullToEmptyString(password), serviceClass, + RILUtils.convertNullToEmptyString(appId)); + }); + } @Override @@ -2464,131 +2312,132 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void setFacilityLockForApp(String facility, boolean lockState, String password, int serviceClass, String appId, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_FACILITY_LOCK, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setFacilityLockForApp", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " facility = " + facility + " lockstate = " + lockState - + " serviceClass = " + serviceClass + " appId = " + appId); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_FACILITY_LOCK, result, mRILDefaultWorkSource); - try { - simProxy.setFacilityLockForApp(rr.mSerial, - RILUtils.convertNullToEmptyString(facility), lockState, - RILUtils.convertNullToEmptyString(password), serviceClass, - RILUtils.convertNullToEmptyString(appId)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setFacilityLockForApp", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " facility = " + facility + " lockstate = " + lockState + + " serviceClass = " + serviceClass + " appId = " + appId); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setFacilityLockForApp", () -> { + simProxy.setFacilityLockForApp(rr.mSerial, + RILUtils.convertNullToEmptyString(facility), lockState, + RILUtils.convertNullToEmptyString(password), serviceClass, + RILUtils.convertNullToEmptyString(appId)); + }); } @Override public void changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("changeBarringPassword", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log all function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + "facility = " + facility); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result, + mRILDefaultWorkSource); - try { - networkProxy.setBarringPassword(rr.mSerial, - RILUtils.convertNullToEmptyString(facility), - RILUtils.convertNullToEmptyString(oldPwd), - RILUtils.convertNullToEmptyString(newPwd)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "changeBarringPassword", e); - } + // Do not log all function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + "facility = " + facility); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "changeBarringPassword", () -> { + networkProxy.setBarringPassword(rr.mSerial, + RILUtils.convertNullToEmptyString(facility), + RILUtils.convertNullToEmptyString(oldPwd), + RILUtils.convertNullToEmptyString(newPwd)); + }); } @Override public void getNetworkSelectionMode(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getNetworkSelectionMode", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, result, + mRILDefaultWorkSource); - try { - networkProxy.getNetworkSelectionMode(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getNetworkSelectionMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getNetworkSelectionMode", () -> { + networkProxy.getNetworkSelectionMode(rr.mSerial); + }); } @Override public void setNetworkSelectionModeAutomatic(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setNetworkSelectionModeAutomatic", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, result, + mRILDefaultWorkSource); - try { - networkProxy.setNetworkSelectionModeAutomatic(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_NETWORK, "setNetworkSelectionModeAutomatic", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setNetworkSelectionModeAutomatic", + () -> { + networkProxy.setNetworkSelectionModeAutomatic(rr.mSerial); + }); } @Override public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setNetworkSelectionModeManual", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " operatorNumeric = " + operatorNumeric + ", ran = " + ran); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, result, + mRILDefaultWorkSource); - try { - networkProxy.setNetworkSelectionModeManual(rr.mSerial, - RILUtils.convertNullToEmptyString(operatorNumeric), ran); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "setNetworkSelectionModeManual", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " operatorNumeric = " + operatorNumeric + ", ran = " + ran); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setNetworkSelectionModeManual", () -> { + networkProxy.setNetworkSelectionModeManual(rr.mSerial, + RILUtils.convertNullToEmptyString(operatorNumeric), ran); + }); } @Override public void getAvailableNetworks(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getAvailableNetworks", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, result, + mRILDefaultWorkSource); - try { - networkProxy.getAvailableNetworks(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getAvailableNetworks", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getAvailableNetworks", () -> { + networkProxy.getAvailableNetworks(rr.mSerial); + }); } /** @@ -2599,526 +2448,486 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void startNetworkScan(NetworkScanRequest networkScanRequest, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { - HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_START_NETWORK_SCAN); - if (RILJ_LOGD) { - riljLog("startNetworkScan: overrideHalVersion=" + overrideHalVersion); - } + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("startNetworkScan", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - RILRequest rr = obtainRequest(RIL_REQUEST_START_NETWORK_SCAN, result, - mRILDefaultWorkSource, networkScanRequest); + HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_START_NETWORK_SCAN); + if (RILJ_LOGD) { + riljLog("startNetworkScan: overrideHalVersion=" + overrideHalVersion); + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_START_NETWORK_SCAN, result, + mRILDefaultWorkSource, networkScanRequest); - try { - networkProxy.startNetworkScan(rr.mSerial, networkScanRequest, overrideHalVersion, - result); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "startNetworkScan", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startNetworkScan: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "startNetworkScan", () -> { + networkProxy.startNetworkScan(rr.mSerial, networkScanRequest, overrideHalVersion, + result); + }); } @Override public void stopNetworkScan(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_STOP_NETWORK_SCAN, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("stopNetworkScan", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STOP_NETWORK_SCAN, result, mRILDefaultWorkSource); - try { - networkProxy.stopNetworkScan(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "stopNetworkScan", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopNetworkScan: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "stopNetworkScan", () -> { + networkProxy.stopNetworkScan(rr.mSerial); + }); } @Override public void startDtmf(char c, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DTMF_START, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("startDtmf", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function arg for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DTMF_START, result, mRILDefaultWorkSource); - try { - voiceProxy.startDtmf(rr.mSerial, c + ""); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "startDtmf", e); - } + // Do not log function arg for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "startDtmf", () -> { + voiceProxy.startDtmf(rr.mSerial, c + ""); + }); } @Override public void stopDtmf(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DTMF_STOP, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("stopDtmf", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DTMF_STOP, result, mRILDefaultWorkSource); - try { - voiceProxy.stopDtmf(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "stopDtmf", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "stopDtmf", () -> { + voiceProxy.stopDtmf(rr.mSerial); + }); } @Override public void separateConnection(int gsmIndex, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEPARATE_CONNECTION, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("separateConnection", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " gsmIndex = " + gsmIndex); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEPARATE_CONNECTION, result, + mRILDefaultWorkSource); - try { - voiceProxy.separateConnection(rr.mSerial, gsmIndex); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "separateConnection", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " gsmIndex = " + gsmIndex); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "separateConnection", () -> { + voiceProxy.separateConnection(rr.mSerial, gsmIndex); + }); } @Override public void getBasebandVersion(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_BASEBAND_VERSION, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getBasebandVersion", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_BASEBAND_VERSION, result, mRILDefaultWorkSource); - try { - modemProxy.getBasebandVersion(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getBasebandVersion", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getBasebandVersion", () -> { + modemProxy.getBasebandVersion(rr.mSerial); + }); } @Override public void setMute(boolean enableMute, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_MUTE, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setMute", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enableMute = " + enableMute); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_MUTE, result, mRILDefaultWorkSource); - try { - voiceProxy.setMute(rr.mSerial, enableMute); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setMute", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enableMute = " + enableMute); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setMute", () -> { + voiceProxy.setMute(rr.mSerial, enableMute); + }); } @Override public void getMute(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_MUTE, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("getMute", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_MUTE, result, mRILDefaultWorkSource); - try { - voiceProxy.getMute(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getMute", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "getMute", () -> { + voiceProxy.getMute(rr.mSerial); + }); } @Override public void queryCLIP(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CLIP, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("queryCLIP", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_CLIP, result, mRILDefaultWorkSource); - try { - voiceProxy.getClip(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getClip", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - /** - * @deprecated - */ - @Override - @Deprecated - public void getPDPContextList(Message result) { - getDataCallList(result); + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "queryCLIP", () -> { + voiceProxy.getClip(rr.mSerial); + }); } @Override public void getDataCallList(Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DATA_CALL_LIST, result, - mRILDefaultWorkSource); + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("getDataCallList", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DATA_CALL_LIST, result, mRILDefaultWorkSource); - try { - dataProxy.getDataCallList(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "getDataCallList", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - - // TODO(b/171260715) Remove when HAL definition is removed - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - } - // TODO(b/171260715) Remove when HAL definition is removed - @Override - public void invokeOemRilRequestStrings(String[] strings, Message result) { + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "getDataCallList", () -> { + dataProxy.getDataCallList(rr.mSerial); + }); } @Override public void setSuppServiceNotifications(boolean enable, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setSuppServiceNotifications", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result, + mRILDefaultWorkSource); - try { - networkProxy.setSuppServiceNotifications(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "setSuppServiceNotifications", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setSuppServiceNotifications", () -> { + networkProxy.setSuppServiceNotifications(rr.mSerial, enable); + }); } @Override public void writeSmsToSim(int status, String smsc, String pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_WRITE_SMS_TO_SIM, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("writeSmsToSim", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGV) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " " + status); - } + RILRequest rr = obtainRequest(RIL_REQUEST_WRITE_SMS_TO_SIM, result, mRILDefaultWorkSource); - try { - messagingProxy.writeSmsToSim(rr.mSerial, status, - RILUtils.convertNullToEmptyString(smsc), - RILUtils.convertNullToEmptyString(pdu)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "writeSmsToSim", e); - } + if (RILJ_LOGV) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + status); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "writeSmsToSim", () -> { + messagingProxy.writeSmsToSim(rr.mSerial, status, + RILUtils.convertNullToEmptyString(smsc), + RILUtils.convertNullToEmptyString(pdu)); + }); } @Override public void deleteSmsOnSim(int index, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DELETE_SMS_ON_SIM, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("deleteSmsOnSim", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGV) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " index = " + index); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DELETE_SMS_ON_SIM, result, mRILDefaultWorkSource); - try { - messagingProxy.deleteSmsOnSim(rr.mSerial, index); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "deleteSmsOnSim", e); - } + if (RILJ_LOGV) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " index = " + index); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "deleteSmsOnSim", () -> { + messagingProxy.deleteSmsOnSim(rr.mSerial, index); + }); } @Override public void setBandMode(int bandMode, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_BAND_MODE, result, mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setBandMode", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " bandMode = " + bandMode); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_BAND_MODE, result, mRILDefaultWorkSource); - try { - networkProxy.setBandMode(rr.mSerial, bandMode); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setBandMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " bandMode = " + bandMode); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setBandMode", () -> { + networkProxy.setBandMode(rr.mSerial, bandMode); + }); } @Override public void queryAvailableBandMode(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("queryAvailableBandMode", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, result, + mRILDefaultWorkSource); - try { - networkProxy.getAvailableBandModes(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "queryAvailableBandMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "queryAvailableBandMode", () -> { + networkProxy.getAvailableBandModes(rr.mSerial); + }); } @Override public void sendEnvelope(String contents, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("sendEnvelope", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " contents = " + contents); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, result, + mRILDefaultWorkSource); - try { - simProxy.sendEnvelope(rr.mSerial, RILUtils.convertNullToEmptyString(contents)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendEnvelope", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " contents = " + contents); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "sendEnvelope", () -> { + simProxy.sendEnvelope(rr.mSerial, RILUtils.convertNullToEmptyString(contents)); + }); } @Override public void sendTerminalResponse(String contents, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("sendTerminalResponse", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " contents = " + (TelephonyUtils.IS_DEBUGGABLE - ? contents : RILUtils.convertToCensoredTerminalResponse(contents))); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, result, + mRILDefaultWorkSource); - try { - simProxy.sendTerminalResponseToSim(rr.mSerial, - RILUtils.convertNullToEmptyString(contents)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendTerminalResponse", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " contents = " + (TelephonyUtils.IS_DEBUGGABLE + ? contents : RILUtils.convertToCensoredTerminalResponse(contents))); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "sendTerminalResponse", () -> { + simProxy.sendTerminalResponseToSim(rr.mSerial, + RILUtils.convertNullToEmptyString(contents)); + }); } @Override public void sendEnvelopeWithStatus(String contents, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("sendEnvelopeWithStatus", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " contents = " + contents); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, result, + mRILDefaultWorkSource); - try { - simProxy.sendEnvelopeWithStatus(rr.mSerial, - RILUtils.convertNullToEmptyString(contents)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendEnvelopeWithStatus", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " contents = " + contents); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "sendEnvelopeWithStatus", () -> { + simProxy.sendEnvelopeWithStatus(rr.mSerial, + RILUtils.convertNullToEmptyString(contents)); + }); } @Override public void explicitCallTransfer(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("explicitCallTransfer", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result, + mRILDefaultWorkSource); - try { - voiceProxy.explicitCallTransfer(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "explicitCallTransfer", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "explicitCallTransfer", () -> { + voiceProxy.explicitCallTransfer(rr.mSerial); + }); } @Override public void setPreferredNetworkType(@PrefNetworkMode int networkType , Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setPreferredNetworkType", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " networkType = " + networkType); - } - mAllowedNetworkTypesBitmask = RadioAccessFamily.getRafFromNetworkType(networkType); - mMetrics.writeSetPreferredNetworkType(mPhoneId, networkType); + RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, result, + mRILDefaultWorkSource); - try { - networkProxy.setPreferredNetworkTypeBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setPreferredNetworkType", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " networkType = " + networkType); } + mAllowedNetworkTypesBitmask = RadioAccessFamily.getRafFromNetworkType(networkType); + mMetrics.writeSetPreferredNetworkType(mPhoneId, networkType); + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setPreferredNetworkType", () -> { + networkProxy.setPreferredNetworkTypeBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); + }); } @Override public void getPreferredNetworkType(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getPreferredNetworkType", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, result, + mRILDefaultWorkSource); - try { - networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getPreferredNetworkType", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getPreferredNetworkType", () -> { + networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); + }); } @Override public void setAllowedNetworkTypesBitmap( @TelephonyManager.NetworkTypeBitMask int networkTypeBitmask, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - if (mHalVersion.get(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_1_6)) { - // For older HAL, redirects the call to setPreferredNetworkType. - setPreferredNetworkType( - RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmask), result); - return; - } - RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP, result, - mRILDefaultWorkSource); + if (mHalVersion.get(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_1_6)) { + // For older HAL, redirects the call to setPreferredNetworkType. + setPreferredNetworkType( + RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmask), result); + return; + } + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setAllowedNetworkTypesBitmap", networkProxy, result, + RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - mAllowedNetworkTypesBitmask = networkTypeBitmask; + RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP, result, + mRILDefaultWorkSource); - try { - networkProxy.setAllowedNetworkTypesBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "setAllowedNetworkTypeBitmask", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + mAllowedNetworkTypesBitmask = networkTypeBitmask; + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setAllowedNetworkTypesBitmap", () -> { + networkProxy.setAllowedNetworkTypesBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); + }); } @Override public void getAllowedNetworkTypesBitmap(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getAllowedNetworkTypesBitmap", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP, result, + mRILDefaultWorkSource); - try { - networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "getAllowedNetworkTypeBitmask", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getAllowedNetworkTypesBitmap", () -> { + networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); + }); } @Override public void setLocationUpdates(boolean enable, WorkSource workSource, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_LOCATION_UPDATES, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setLocationUpdates", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_LOCATION_UPDATES, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - networkProxy.setLocationUpdates(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setLocationUpdates", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setLocationUpdates", () -> { + networkProxy.setLocationUpdates(rr.mSerial, enable); + }); } /** @@ -3126,32 +2935,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isNrDualConnectivityEnabled(Message result, WorkSource workSource) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("isNrDualConnectivityEnabled", networkProxy, result, + RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - networkProxy.isNrDualConnectivityEnabled(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "isNrDualConnectivityEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "isNrDualConnectivityEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "isNrDualConnectivityEnabled", () -> { + networkProxy.isNrDualConnectivityEnabled(rr.mSerial); + }); } /** @@ -3168,30 +2967,23 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void setNrDualConnectivityState(int nrDualConnectivityState, Message result, WorkSource workSource) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setNrDualConnectivityState", networkProxy, result, + RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + nrDualConnectivityState); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - networkProxy.setNrDualConnectivityState(rr.mSerial, (byte) nrDualConnectivityState); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "enableNrDualConnectivity", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "enableNrDualConnectivity: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + nrDualConnectivityState); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setNrDualConnectivityState", () -> { + networkProxy.setNrDualConnectivityState(rr.mSerial, (byte) nrDualConnectivityState); + }); } private void setVoNrEnabled(boolean enabled) { @@ -3207,30 +2999,27 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isVoNrEnabled(Message result, WorkSource workSource) { - - if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_IS_VONR_ENABLED , result, - getDefaultWorkSourceIfInvalid(workSource)); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - voiceProxy.isVoNrEnabled(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "isVoNrEnabled", e); - } - } - } else { + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + // Send null result so errors aren't sent in canMakeRequest + if (!canMakeRequest("isVoNrEnabled", voiceProxy, null, RADIO_HAL_VERSION_2_0)) { boolean isEnabled = isVoNrEnabled(); if (result != null) { AsyncResult.forMessage(result, isEnabled, null); result.sendToTarget(); } + return; } + + RILRequest rr = obtainRequest(RIL_REQUEST_IS_VONR_ENABLED, result, + getDefaultWorkSourceIfInvalid(workSource)); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "isVoNrEnabled", () -> { + voiceProxy.isVoNrEnabled(rr.mSerial); + }); } /** @@ -3240,24 +3029,9 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void setVoNrEnabled(boolean enabled, Message result, WorkSource workSource) { setVoNrEnabled(enabled); - - if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_VONR, result, - getDefaultWorkSourceIfInvalid(workSource)); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - voiceProxy.setVoNrEnabled(rr.mSerial, enabled); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setVoNrEnabled", e); - } - } - } else { + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + // Send null result so errors aren't sent in canMakeRequest + if (!canMakeRequest("setVoNrEnabled", voiceProxy, null, RADIO_HAL_VERSION_2_0)) { /* calling a query api to let HAL know that VoNREnabled state is updated. This is a work around as new AIDL API is not allowed for older HAL version devices. HAL can check the value of PROPERTY_IS_VONR_ENABLED property to determine @@ -3268,858 +3042,839 @@ public class RIL extends BaseCommands implements CommandsInterface { AsyncResult.forMessage(result, null, null); result.sendToTarget(); } + return; } + + RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_VONR, result, + getDefaultWorkSourceIfInvalid(workSource)); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setVoNrEnabled", () -> { + voiceProxy.setVoNrEnabled(rr.mSerial, enabled); + }); } @Override public void setCdmaSubscriptionSource(int cdmaSubscription, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setCdmaSubscriptionSource", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " cdmaSubscription = " + cdmaSubscription); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, result, + mRILDefaultWorkSource); - try { - simProxy.setCdmaSubscriptionSource(rr.mSerial, cdmaSubscription); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setCdmaSubscriptionSource", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " cdmaSubscription = " + cdmaSubscription); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setCdmaSubscriptionSource", () -> { + simProxy.setCdmaSubscriptionSource(rr.mSerial, cdmaSubscription); + }); } @Override public void queryCdmaRoamingPreference(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("queryCdmaRoamingPreference", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, result, + mRILDefaultWorkSource); - try { - networkProxy.getCdmaRoamingPreference(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "queryCdmaRoamingPreference", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "queryCdmaRoamingPreference", () -> { + networkProxy.getCdmaRoamingPreference(rr.mSerial); + }); } @Override public void setCdmaRoamingPreference(int cdmaRoamingType, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setCdmaRoamingPreference", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " cdmaRoamingType = " + cdmaRoamingType); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, result, + mRILDefaultWorkSource); - try { - networkProxy.setCdmaRoamingPreference(rr.mSerial, cdmaRoamingType); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setCdmaRoamingPreference", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " cdmaRoamingType = " + cdmaRoamingType); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setCdmaRoamingPreference", () -> { + networkProxy.setCdmaRoamingPreference(rr.mSerial, cdmaRoamingType); + }); } @Override public void queryTTYMode(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_TTY_MODE, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("queryTTYMode", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_QUERY_TTY_MODE, result, mRILDefaultWorkSource); - try { - voiceProxy.getTtyMode(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getTtyMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "queryTTYMode", () -> { + voiceProxy.getTtyMode(rr.mSerial); + }); } @Override public void setTTYMode(int ttyMode, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_TTY_MODE, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setTTYMode", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " ttyMode = " + ttyMode); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_TTY_MODE, result, mRILDefaultWorkSource); - try { - voiceProxy.setTtyMode(rr.mSerial, ttyMode); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setTtyMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " ttyMode = " + ttyMode); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setTTYMode", () -> { + voiceProxy.setTtyMode(rr.mSerial, ttyMode); + }); } @Override public void setPreferredVoicePrivacy(boolean enable, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("setPreferredVoicePrivacy", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable = " + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, result, + mRILDefaultWorkSource); - try { - voiceProxy.setPreferredVoicePrivacy(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setPreferredVoicePrivacy", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable = " + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "setPreferredVoicePrivacy", () -> { + voiceProxy.setPreferredVoicePrivacy(rr.mSerial, enable); + }); } @Override public void getPreferredVoicePrivacy(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, - result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("getPreferredVoicePrivacy", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, + result, mRILDefaultWorkSource); - try { - voiceProxy.getPreferredVoicePrivacy(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getPreferredVoicePrivacy", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "getPreferredVoicePrivacy", () -> { + voiceProxy.getPreferredVoicePrivacy(rr.mSerial); + }); } @Override public void sendCDMAFeatureCode(String featureCode, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_FLASH, result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("sendCDMAFeatureCode", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " featureCode = " + Rlog.pii(RILJ_LOG_TAG, featureCode)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_FLASH, result, mRILDefaultWorkSource); - try { - voiceProxy.sendCdmaFeatureCode(rr.mSerial, - RILUtils.convertNullToEmptyString(featureCode)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendCdmaFeatureCode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " featureCode = " + Rlog.pii(RILJ_LOG_TAG, featureCode)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "sendCDMAFeatureCode", () -> { + voiceProxy.sendCdmaFeatureCode(rr.mSerial, + RILUtils.convertNullToEmptyString(featureCode)); + }); } @Override public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_BURST_DTMF, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("sendBurstDtmf", voiceProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " dtmfString = " + dtmfString + " on = " + on + " off = " + off); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_BURST_DTMF, result, mRILDefaultWorkSource); - try { - voiceProxy.sendBurstDtmf(rr.mSerial, RILUtils.convertNullToEmptyString(dtmfString), - on, off); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendBurstDtmf", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " dtmfString = " + dtmfString + " on = " + on + " off = " + off); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "sendBurstDtmf", () -> { + voiceProxy.sendBurstDtmf(rr.mSerial, RILUtils.convertNullToEmptyString(dtmfString), + on, off); + }); } @Override public void sendCdmaSMSExpectMore(byte[] pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendCdmaSMSExpectMore", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function arg for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE, result, + mRILDefaultWorkSource); - try { - messagingProxy.sendCdmaSmsExpectMore(rr.mSerial, pdu); - if (mHalVersion.get(HAL_SERVICE_MESSAGING).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, - SmsSession.Event.Format.SMS_FORMAT_3GPP2, - getOutgoingSmsMessageId(result)); - } - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendCdmaSMSExpectMore", e); - } + // Do not log function arg for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendCdmaSMSExpectMore", () -> { + messagingProxy.sendCdmaSmsExpectMore(rr.mSerial, pdu); + if (mHalVersion.get(HAL_SERVICE_MESSAGING).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, + SmsSession.Event.Format.SMS_FORMAT_3GPP2, + getOutgoingSmsMessageId(result)); + } + }); } @Override public void sendCdmaSms(byte[] pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS, result, mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendCdmaSms", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function arg for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SEND_SMS, result, mRILDefaultWorkSource); - try { - messagingProxy.sendCdmaSms(rr.mSerial, pdu); - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, - SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendCdmaSms", e); - } + // Do not log function arg for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendCdmaSms", () -> { + messagingProxy.sendCdmaSms(rr.mSerial, pdu); + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, + SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); + }); } @Override public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("acknowledgeLastIncomingCdmaSms", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " success = " + success + " cause = " + cause); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result, + mRILDefaultWorkSource); - try { - messagingProxy.acknowledgeLastIncomingCdmaSms(rr.mSerial, success, cause); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, - "acknowledgeLastIncomingCdmaSms", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " success = " + success + " cause = " + cause); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "acknowledgeLastIncomingCdmaSms", + () -> { + messagingProxy.acknowledgeLastIncomingCdmaSms(rr.mSerial, success, cause); + }); } @Override public void getGsmBroadcastConfig(Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GSM_GET_BROADCAST_CONFIG, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("getGsmBroadcastConfig", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GSM_GET_BROADCAST_CONFIG, result, + mRILDefaultWorkSource); - try { - messagingProxy.getGsmBroadcastConfig(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getGsmBroadcastConfig", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "getGsmBroadcastConfig", () -> { + messagingProxy.getGsmBroadcastConfig(rr.mSerial); + }); } @Override public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GSM_SET_BROADCAST_CONFIG, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("setGsmBroadcastConfig", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " with " + config.length + " configs : "); - for (int i = 0; i < config.length; i++) { - riljLog(config[i].toString()); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_GSM_SET_BROADCAST_CONFIG, result, + mRILDefaultWorkSource); - try { - messagingProxy.setGsmBroadcastConfig(rr.mSerial, config); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setGsmBroadcastConfig", e); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " with " + config.length + " configs : "); + for (int i = 0; i < config.length; i++) { + riljLog(config[i].toString()); } } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "setGsmBroadcastConfig", () -> { + messagingProxy.setGsmBroadcastConfig(rr.mSerial, config); + }); } @Override public void setGsmBroadcastActivation(boolean activate, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GSM_BROADCAST_ACTIVATION, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("setGsmBroadcastActivation", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " activate = " + activate); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GSM_BROADCAST_ACTIVATION, result, + mRILDefaultWorkSource); - try { - messagingProxy.setGsmBroadcastActivation(rr.mSerial, activate); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, - "setGsmBroadcastActivation", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " activate = " + activate); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "setGsmBroadcastActivation", () -> { + messagingProxy.setGsmBroadcastActivation(rr.mSerial, activate); + }); } @Override public void getCdmaBroadcastConfig(Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("getCdmaBroadcastConfig", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, result, + mRILDefaultWorkSource); - try { - messagingProxy.getCdmaBroadcastConfig(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getCdmaBroadcastConfig", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "getCdmaBroadcastConfig", () -> { + messagingProxy.getCdmaBroadcastConfig(rr.mSerial); + }); } @Override public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("setCdmaBroadcastConfig", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " with " + configs.length + " configs : "); - for (CdmaSmsBroadcastConfigInfo config : configs) { - riljLog(config.toString()); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, result, + mRILDefaultWorkSource); - try { - messagingProxy.setCdmaBroadcastConfig(rr.mSerial, configs); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setCdmaBroadcastConfig", e); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " with " + configs.length + " configs : "); + for (CdmaSmsBroadcastConfigInfo config : configs) { + riljLog(config.toString()); } } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "setCdmaBroadcastConfig", () -> { + messagingProxy.setCdmaBroadcastConfig(rr.mSerial, configs); + }); } @Override public void setCdmaBroadcastActivation(boolean activate, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("setCdmaBroadcastActivation", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " activate = " + activate); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, result, + mRILDefaultWorkSource); - try { - messagingProxy.setCdmaBroadcastActivation(rr.mSerial, activate); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, - "setCdmaBroadcastActivation", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " activate = " + activate); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "setCdmaBroadcastActivation", () -> { + messagingProxy.setCdmaBroadcastActivation(rr.mSerial, activate); + }); } @Override public void getCDMASubscription(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SUBSCRIPTION, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getCDMASubscription", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SUBSCRIPTION, result, mRILDefaultWorkSource); - try { - simProxy.getCdmaSubscription(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getCdmaSubscription", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getCDMASubscription", () -> { + simProxy.getCdmaSubscription(rr.mSerial); + }); } @Override public void writeSmsToRuim(int status, byte[] pdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("writeSmsToRuim", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGV) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " status = " + status); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, result, + mRILDefaultWorkSource); - try { - messagingProxy.writeSmsToRuim(rr.mSerial, status, pdu); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "writeSmsToRuim", e); - } + if (RILJ_LOGV) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " status = " + status); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "writeSmsToRuim", () -> { + messagingProxy.writeSmsToRuim(rr.mSerial, status, pdu); + }); } @Override public void deleteSmsOnRuim(int index, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("deleteSmsOnRuim", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGV) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " index = " + index); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, result, + mRILDefaultWorkSource); - try { - messagingProxy.deleteSmsOnRuim(rr.mSerial, index); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "deleteSmsOnRuim", e); - } + if (RILJ_LOGV) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " index = " + index); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "deleteSmsOnRuim", () -> { + messagingProxy.deleteSmsOnRuim(rr.mSerial, index); + }); } @Override public void getDeviceIdentity(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IDENTITY, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getDeviceIdentity", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IDENTITY, result, mRILDefaultWorkSource); - try { - modemProxy.getDeviceIdentity(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getDeviceIdentity", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getDeviceIdentity", () -> { + modemProxy.getDeviceIdentity(rr.mSerial); + }); } @Override public void getImei(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (modemProxy.isEmpty()) { - if (RILJ_LOGD) { - Rlog.e(RILJ_LOG_TAG, "getImei: modemProxy is Empty"); - } + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getImei", modemProxy, result, RADIO_HAL_VERSION_2_1)) { return; } - if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IMEI, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IMEI, result, mRILDefaultWorkSource); - try { - modemProxy.getImei(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getImei", e); - } - } else { - if (RILJ_LOGD) { - Rlog.e(RILJ_LOG_TAG, "getImei: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getImei", () -> { + modemProxy.getImei(rr.mSerial); + }); } @Override public void exitEmergencyCallbackMode(Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, result, - mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("exitEmergencyCallbackMode", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, result, + mRILDefaultWorkSource); - try { - voiceProxy.exitEmergencyCallbackMode(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "exitEmergencyCallbackMode", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "exitEmergencyCallbackMode", () -> { + voiceProxy.exitEmergencyCallbackMode(rr.mSerial); + }); } @Override public void getSmscAddress(Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SMSC_ADDRESS, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("getSmscAddress", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SMSC_ADDRESS, result, mRILDefaultWorkSource); - try { - messagingProxy.getSmscAddress(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getSmscAddress", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "getSmscAddress", () -> { + messagingProxy.getSmscAddress(rr.mSerial); + }); } @Override public void setSmscAddress(String address, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SMSC_ADDRESS, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("setSmscAddress", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " address = " + address); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SMSC_ADDRESS, result, mRILDefaultWorkSource); - try { - messagingProxy.setSmscAddress(rr.mSerial, - RILUtils.convertNullToEmptyString(address)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setSmscAddress", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " address = " + address); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "setSmscAddress", () -> { + messagingProxy.setSmscAddress(rr.mSerial, RILUtils.convertNullToEmptyString(address)); + }); } @Override public void reportSmsMemoryStatus(boolean available, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("reportSmsMemoryStatus", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " available = " + available); - } + RILRequest rr = obtainRequest(RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, result, + mRILDefaultWorkSource); - try { - messagingProxy.reportSmsMemoryStatus(rr.mSerial, available); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "reportSmsMemoryStatus", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " available = " + available); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "reportSmsMemoryStatus", () -> { + messagingProxy.reportSmsMemoryStatus(rr.mSerial, available); + }); } @Override public void reportStkServiceIsRunning(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("reportStkServiceIsRunning", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, result, + mRILDefaultWorkSource); - try { - simProxy.reportStkServiceIsRunning(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "reportStkServiceIsRunning", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "reportStkServiceIsRunning", () -> { + simProxy.reportStkServiceIsRunning(rr.mSerial); + }); } @Override public void getCdmaSubscriptionSource(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getCdmaSubscriptionSource", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, result, + mRILDefaultWorkSource); - try { - simProxy.getCdmaSubscriptionSource(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getCdmaSubscriptionSource", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getCdmaSubscriptionSource", () -> { + simProxy.getCdmaSubscriptionSource(rr.mSerial); + }); } @Override public void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, result, - mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("acknowledgeIncomingGsmSmsWithPdu", messagingProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " success = " + success); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, result, + mRILDefaultWorkSource); - try { - messagingProxy.acknowledgeIncomingGsmSmsWithPdu(rr.mSerial, success, - RILUtils.convertNullToEmptyString(ackPdu)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, - "acknowledgeIncomingGsmSmsWithPdu", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " success = " + success); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "acknowledgeIncomingGsmSmsWithPdu", + () -> { + messagingProxy.acknowledgeIncomingGsmSmsWithPdu(rr.mSerial, success, + RILUtils.convertNullToEmptyString(ackPdu)); + }); } @Override public void getVoiceRadioTechnology(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_RADIO_TECH, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getVoiceRadioTechnology", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_RADIO_TECH, result, mRILDefaultWorkSource); - try { - networkProxy.getVoiceRadioTechnology(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getVoiceRadioTechnology", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getVoiceRadioTechnology", () -> { + networkProxy.getVoiceRadioTechnology(rr.mSerial); + }); } @Override public void getCellInfoList(Message result, WorkSource workSource) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_CELL_INFO_LIST, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getCellInfoList", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_CELL_INFO_LIST, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - networkProxy.getCellInfoList(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getCellInfoList", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getCellInfoList", () -> { + networkProxy.getCellInfoList(rr.mSerial); + }); } @Override public void setCellInfoListRate(int rateInMillis, Message result, WorkSource workSource) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setCellInfoListRate", networkProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " rateInMillis = " + rateInMillis); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - networkProxy.setCellInfoListRate(rr.mSerial, rateInMillis); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setCellInfoListRate", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " rateInMillis = " + rateInMillis); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setCellInfoListRate", () -> { + networkProxy.setCellInfoListRate(rr.mSerial, rateInMillis); + }); } @Override - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_INITIAL_ATTACH_APN, result, - mRILDefaultWorkSource); + public void setInitialAttachApn(DataProfile dataProfile, Message result) { + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("setInitialAttachApn", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + dataProfile); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_INITIAL_ATTACH_APN, result, + mRILDefaultWorkSource); - try { - dataProxy.setInitialAttachApn(rr.mSerial, dataProfile, isRoaming); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setInitialAttachApn", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + dataProfile); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "setInitialAttachApn", () -> { + dataProxy.setInitialAttachApn(rr.mSerial, dataProfile); + }); } @Override public void getImsRegistrationState(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_IMS_REGISTRATION_STATE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getImsRegistrationState", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IMS_REGISTRATION_STATE, result, + mRILDefaultWorkSource); - try { - networkProxy.getImsRegistrationState(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getImsRegistrationState", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getImsRegistrationState", () -> { + networkProxy.getImsRegistrationState(rr.mSerial); + }); } @Override public void sendImsGsmSms(String smscPdu, String pdu, int retry, int messageRef, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_IMS_SEND_SMS, result, mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendImsGsmSms", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IMS_SEND_SMS, result, mRILDefaultWorkSource); - try { - messagingProxy.sendImsSms(rr.mSerial, smscPdu, pdu, null, retry, messageRef); - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, - SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendImsGsmSms", e); - } + // Do not log function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendImsGsmSms", () -> { + messagingProxy.sendImsSms(rr.mSerial, smscPdu, pdu, null, retry, messageRef); + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, + SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); + }); } @Override public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef, Message result) { - RadioMessagingProxy messagingProxy = - getRadioServiceProxy(RadioMessagingProxy.class, result); - if (!messagingProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_IMS_SEND_SMS, result, mRILDefaultWorkSource); + RadioMessagingProxy messagingProxy = getRadioServiceProxy(RadioMessagingProxy.class); + if (!canMakeRequest("sendImsCdmaSms", messagingProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IMS_SEND_SMS, result, mRILDefaultWorkSource); - try { - messagingProxy.sendImsSms(rr.mSerial, null, null, pdu, retry, messageRef); - mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, - SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendImsCdmaSms", e); - } + // Do not log function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MESSAGING, rr, "sendImsCdmaSms", () -> { + messagingProxy.sendImsSms(rr.mSerial, null, null, pdu, retry, messageRef); + mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, + SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); + }); } @Override public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("iccTransmitApduBasicChannel", simProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - if (TelephonyUtils.IS_DEBUGGABLE) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction) - + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3) - + " data = " + data); - } else { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC, result, + mRILDefaultWorkSource); - try { - simProxy.iccTransmitApduBasicChannel( - rr.mSerial, cla, instruction, p1, p2, p3, data); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccTransmitApduBasicChannel", e); + if (RILJ_LOGD) { + if (TelephonyUtils.IS_DEBUGGABLE) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction) + + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3) + + " data = " + data); + } else { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "iccTransmitApduBasicChannel", () -> { + simProxy.iccTransmitApduBasicChannel(rr.mSerial, cla, instruction, p1, p2, p3, data); + }); } @Override public void iccOpenLogicalChannel(String aid, int p2, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_OPEN_CHANNEL, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("iccOpenLogicalChannel", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - if (TelephonyUtils.IS_DEBUGGABLE) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " aid = " + aid + " p2 = " + p2); - } else { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_OPEN_CHANNEL, result, mRILDefaultWorkSource); - try { - simProxy.iccOpenLogicalChannel(rr.mSerial, RILUtils.convertNullToEmptyString(aid), - p2); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccOpenLogicalChannel", e); + if (RILJ_LOGD) { + if (TelephonyUtils.IS_DEBUGGABLE) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " aid = " + aid + " p2 = " + p2); + } else { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "iccOpenLogicalChannel", () -> { + simProxy.iccOpenLogicalChannel(rr.mSerial, RILUtils.convertNullToEmptyString(aid), p2); + }); } @Override public void iccCloseLogicalChannel(int channel, boolean isEs10, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_CLOSE_CHANNEL, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("iccCloseLogicalChannel", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " channel = " + channel + " isEs10 = " + isEs10); - } - try { - simProxy.iccCloseLogicalChannel(rr.mSerial, channel, isEs10); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccCloseLogicalChannel", e); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_CLOSE_CHANNEL, result, mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " channel = " + channel + " isEs10 = " + isEs10); } + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "iccCloseLogicalChannel", () -> { + simProxy.iccCloseLogicalChannel(rr.mSerial, channel, isEs10); + }); } @Override @@ -4130,351 +3885,276 @@ public class RIL extends BaseCommands implements CommandsInterface { "Invalid channel in iccTransmitApduLogicalChannel: " + channel); } - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("iccTransmitApduLogicalChannel", simProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - if (TelephonyUtils.IS_DEBUGGABLE) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + String.format(" channel = %d", channel) - + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction) - + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3) - + " isEs10Command = " + isEs10Command - + " data = " + data); - } else { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL, result, + mRILDefaultWorkSource); - try { - simProxy.iccTransmitApduLogicalChannel( - rr.mSerial, channel, cla, instruction, p1, p2, p3, data, isEs10Command); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccTransmitApduLogicalChannel", e); + if (RILJ_LOGD) { + if (TelephonyUtils.IS_DEBUGGABLE) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + String.format(" channel = %d", channel) + + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction) + + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3) + + " isEs10Command = " + isEs10Command + + " data = " + data); + } else { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "iccTransmitApduLogicalChannel", () -> { + simProxy.iccTransmitApduLogicalChannel(rr.mSerial, channel, cla, instruction, p1, p2, + p3, data, isEs10Command); + }); } @Override public void nvReadItem(int itemID, Message result, WorkSource workSource) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_NV_READ_ITEM, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("nvReadItem", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " itemId = " + itemID); - } + RILRequest rr = obtainRequest(RIL_REQUEST_NV_READ_ITEM, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - modemProxy.nvReadItem(rr.mSerial, itemID); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvReadItem", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " itemId = " + itemID); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "nvReadItem", () -> { + modemProxy.nvReadItem(rr.mSerial, itemID); + }); } @Override public void nvWriteItem(int itemId, String itemValue, Message result, WorkSource workSource) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_NV_WRITE_ITEM, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("nvWriteItem", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " itemId = " + itemId + " itemValue = " + itemValue); - } + RILRequest rr = obtainRequest(RIL_REQUEST_NV_WRITE_ITEM, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - modemProxy.nvWriteItem(rr.mSerial, itemId, - RILUtils.convertNullToEmptyString(itemValue)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvWriteItem", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " itemId = " + itemId + " itemValue = " + itemValue); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "nvWriteItem", () -> { + modemProxy.nvWriteItem(rr.mSerial, itemId, + RILUtils.convertNullToEmptyString(itemValue)); + }); } @Override public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_NV_WRITE_CDMA_PRL, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("nvWriteCdmaPrl", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " PreferredRoamingList = 0x" - + IccUtils.bytesToHexString(preferredRoamingList)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_NV_WRITE_CDMA_PRL, result, mRILDefaultWorkSource); - try { - modemProxy.nvWriteCdmaPrl(rr.mSerial, preferredRoamingList); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvWriteCdmaPrl", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " PreferredRoamingList = 0x" + + IccUtils.bytesToHexString(preferredRoamingList)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "nvWriteCdmaPrl", () -> { + modemProxy.nvWriteCdmaPrl(rr.mSerial, preferredRoamingList); + }); } @Override public void nvResetConfig(int resetType, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_NV_RESET_CONFIG, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("nvResetConfig", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " resetType = " + resetType); - } + RILRequest rr = obtainRequest(RIL_REQUEST_NV_RESET_CONFIG, result, mRILDefaultWorkSource); - try { - modemProxy.nvResetConfig(rr.mSerial, resetType); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvResetConfig", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " resetType = " + resetType); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "nvResetConfig", () -> { + modemProxy.nvResetConfig(rr.mSerial, resetType); + }); } @Override public void setUiccSubscription(int slotId, int appIndex, int subId, int subStatus, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setUiccSubscription", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " slot = " + slotId + " appIndex = " + appIndex - + " subId = " + subId + " subStatus = " + subStatus); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result, + mRILDefaultWorkSource); - try { - simProxy.setUiccSubscription(rr.mSerial, slotId, appIndex, subId, subStatus); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setUiccSubscription", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " slot = " + slotId + " appIndex = " + appIndex + + " subId = " + subId + " subStatus = " + subStatus); } - } - /** - * Whether the device modem supports reporting the EID in either the slot or card status or - * through ATR. - * @return true if the modem supports EID. - */ - @Override - public boolean supportsEid() { - // EID should be supported as long as HAL >= 1.2. - // - in HAL 1.2 we have EID through ATR - // - in later HAL versions we also have EID through slot / card status. - return mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2); + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setUiccSubscription", () -> { + simProxy.setUiccSubscription(rr.mSerial, slotId, appIndex, subId, subStatus); + }); } @Override public void setDataAllowed(boolean allowed, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_ALLOW_DATA, result, mRILDefaultWorkSource); + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("setDataAllowed", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " allowed = " + allowed); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ALLOW_DATA, result, mRILDefaultWorkSource); - try { - dataProxy.setDataAllowed(rr.mSerial, allowed); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataAllowed", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " allowed = " + allowed); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "setDataAllowed", () -> { + dataProxy.setDataAllowed(rr.mSerial, allowed); + }); } @Override public void getHardwareConfig(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_HARDWARE_CONFIG, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getHardwareConfig", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_HARDWARE_CONFIG, result, + mRILDefaultWorkSource); - try { - modemProxy.getHardwareConfig(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getHardwareConfig", e); - } + // Do not log function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getHardwareConfig", () -> { + modemProxy.getHardwareConfig(rr.mSerial); + }); } @Override public void requestIccSimAuthentication(int authContext, String data, String aid, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SIM_AUTHENTICATION, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("requestIccSimAuthentication", simProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - // Do not log function args for privacy - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SIM_AUTHENTICATION, result, + mRILDefaultWorkSource); - try { - simProxy.requestIccSimAuthentication(rr.mSerial, authContext, - RILUtils.convertNullToEmptyString(data), - RILUtils.convertNullToEmptyString(aid)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "requestIccSimAuthentication", e); - } + // Do not log function args for privacy + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "requestIccSimAuthentication", () -> { + simProxy.requestIccSimAuthentication(rr.mSerial, authContext, + RILUtils.convertNullToEmptyString(data), + RILUtils.convertNullToEmptyString(aid)); + }); } @Override - public void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (!dataProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_DATA_PROFILE, result, - mRILDefaultWorkSource); + public void setDataProfile(DataProfile[] dps, Message result) { + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("setDataProfile", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " with data profiles : "); - for (DataProfile profile : dps) { - riljLog(profile.toString()); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_DATA_PROFILE, result, mRILDefaultWorkSource); - try { - dataProxy.setDataProfile(rr.mSerial, dps, isRoaming); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataProfile", e); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " with data profiles : "); + for (DataProfile profile : dps) { + riljLog(profile.toString()); } } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "setDataProfile", () -> { + dataProxy.setDataProfile(rr.mSerial, dps); + }); } @Override public void requestShutdown(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SHUTDOWN, result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - modemProxy.requestShutdown(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "requestShutdown", e); - } + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("requestShutdown", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; } - } - @Override - public void getRadioCapability(Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_RADIO_CAPABILITY, result, - mRILDefaultWorkSource); + RILRequest rr = obtainRequest(RIL_REQUEST_SHUTDOWN, result, mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - modemProxy.getRadioCapability(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getRadioCapability", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - - @Override - public void setRadioCapability(RadioCapability rc, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_RADIO_CAPABILITY, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " RadioCapability = " + rc.toString()); - } - try { - modemProxy.setRadioCapability(rr.mSerial, rc); - } catch (Exception e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "setRadioCapability", e); - } - } + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "requestShutdown", () -> { + modemProxy.requestShutdown(rr.mSerial); + }); } @Override - public void startLceService(int reportIntervalMs, boolean pullMode, Message result) { - if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { - // We have a 1.2 or later radio, so the LCE 1.0 LCE service control path is unused. - // Instead the LCE functionality is always-on and provides unsolicited indications. - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startLceService: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + public void getRadioCapability(Message result) { + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getRadioCapability", modemProxy, result, RADIO_HAL_VERSION_1_4)) { return; } - IRadio radioProxy = getRadioProxy(result); - if (radioProxy != null) { - RILRequest rr = obtainRequest(RIL_REQUEST_START_LCE, result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " reportIntervalMs = " + reportIntervalMs + " pullMode = " + pullMode); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_RADIO_CAPABILITY, result, + mRILDefaultWorkSource); - try { - radioProxy.startLceService(rr.mSerial, reportIntervalMs, pullMode); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "startLceService", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getRadioCapability", () -> { + modemProxy.getRadioCapability(rr.mSerial); + }); } @Override - public void stopLceService(Message result) { - if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { - // We have a 1.2 or later radio, so the LCE 1.0 LCE service control is unused. - // Instead the LCE functionality is always-on and provides unsolicited indications. - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopLceService: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + public void setRadioCapability(RadioCapability rc, Message result) { + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("setRadioCapability", modemProxy, result, RADIO_HAL_VERSION_1_4)) { return; } - IRadio radioProxy = getRadioProxy(result); - if (radioProxy != null) { - RILRequest rr = obtainRequest(RIL_REQUEST_STOP_LCE, result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_RADIO_CAPABILITY, result, + mRILDefaultWorkSource); - try { - radioProxy.stopLceService(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "stopLceService", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " RadioCapability = " + rc.toString()); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "setRadioCapability", () -> { + modemProxy.setRadioCapability(rr.mSerial, rc); + }); } /** @@ -4489,96 +4169,45 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void setDataThrottling(Message result, WorkSource workSource, int dataThrottlingAction, long completionWindowMillis) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_DATA_THROTTLING, result, - getDefaultWorkSourceIfInvalid(workSource)); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " - + RILUtils.requestToString(rr.mRequest) - + " dataThrottlingAction = " + dataThrottlingAction - + " completionWindowMillis " + completionWindowMillis); - } - - try { - dataProxy.setDataThrottling(rr.mSerial, (byte) dataThrottlingAction, - completionWindowMillis); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataThrottling", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "setDataThrottling: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - } - - /** - * This will only be called if the LCE service is started in PULL mode, which is - * only enabled when using Radio HAL versions 1.1 and earlier. - * - * It is still possible for vendors to override this behavior and use the 1.1 version - * of LCE; however, this is strongly discouraged and this functionality will be removed - * when HAL 1.x support is dropped. - * - * @deprecated HAL 1.2 and later use an always-on LCE that relies on indications. - */ - @Deprecated - @Override - public void pullLceData(Message result) { - if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { - // We have a 1.2 or later radio, so the LCE 1.0 LCE service control path is unused. - // Instead the LCE functionality is always-on and provides unsolicited indications. - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "pullLceData: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("setDataThrottling", dataProxy, result, RADIO_HAL_VERSION_1_6)) { return; } - IRadio radioProxy = getRadioProxy(result); - if (radioProxy != null) { - RILRequest rr = obtainRequest(RIL_REQUEST_PULL_LCEDATA, result, mRILDefaultWorkSource); + RILRequest rr = obtainRequest(RIL_REQUEST_SET_DATA_THROTTLING, result, + getDefaultWorkSourceIfInvalid(workSource)); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioProxy.pullLceData(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "pullLceData", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " dataThrottlingAction = " + dataThrottlingAction + + " completionWindowMillis " + completionWindowMillis); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "setDataThrottling", () -> { + dataProxy.setDataThrottling(rr.mSerial, (byte) dataThrottlingAction, + completionWindowMillis); + }); } @Override public void getModemActivityInfo(Message result, WorkSource workSource) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_ACTIVITY_INFO, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("getModemActivityInfo", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_ACTIVITY_INFO, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - modemProxy.getModemActivityInfo(rr.mSerial); - Message msg = - mRilHandler.obtainMessage(EVENT_BLOCKING_RESPONSE_TIMEOUT, rr.mSerial); - mRilHandler.sendMessageDelayed(msg, DEFAULT_BLOCKING_MESSAGE_RESPONSE_TIMEOUT_MS); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getModemActivityInfo", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "getModemActivityInfo", () -> { + modemProxy.getModemActivityInfo(rr.mSerial); + Message msg = mRilHandler.obtainMessage(EVENT_BLOCKING_RESPONSE_TIMEOUT, rr.mSerial); + mRilHandler.sendMessageDelayed(msg, DEFAULT_BLOCKING_MESSAGE_RESPONSE_TIMEOUT_MS); + }); } @Override @@ -4586,266 +4215,208 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result, WorkSource workSource) { Objects.requireNonNull(carrierRestrictionRules, "Carrier restriction cannot be null."); - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_CARRIERS, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setAllowedCarriers", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " params: " + carrierRestrictionRules); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_CARRIERS, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - simProxy.setAllowedCarriers(rr.mSerial, carrierRestrictionRules, result); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setAllowedCarriers", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " params: " + carrierRestrictionRules); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setAllowedCarriers", () -> { + simProxy.setAllowedCarriers(rr.mSerial, carrierRestrictionRules); + }); } @Override public void getAllowedCarriers(Message result, WorkSource workSource) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_CARRIERS, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getAllowedCarriers", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_CARRIERS, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - simProxy.getAllowedCarriers(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getAllowedCarriers", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getAllowedCarriers", () -> { + simProxy.getAllowedCarriers(rr.mSerial); + }); } @Override public void sendDeviceState(int stateType, boolean state, Message result) { - RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEND_DEVICE_STATE, result, - mRILDefaultWorkSource); + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class); + if (!canMakeRequest("sendDeviceState", modemProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " " - + stateType + ":" + state); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_DEVICE_STATE, result, mRILDefaultWorkSource); - try { - modemProxy.sendDeviceState(rr.mSerial, stateType, state); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "sendDeviceState", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " " + + stateType + ":" + state); } + + radioServiceInvokeHelper(HAL_SERVICE_MODEM, rr, "sendDeviceState", () -> { + modemProxy.sendDeviceState(rr.mSerial, stateType, state); + }); } @Override public void setUnsolResponseFilter(int filter, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (!networkProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setUnsolResponseFilter", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " " + filter); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER, result, + mRILDefaultWorkSource); - try { - networkProxy.setIndicationFilter(rr.mSerial, filter); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setIndicationFilter", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + filter); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setUnsolResponseFilter", () -> { + networkProxy.setIndicationFilter(rr.mSerial, filter); + }); } @Override public void setSignalStrengthReportingCriteria( @NonNull List<SignalThresholdInfo> signalThresholdInfos, @Nullable Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA, - result, mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setSignalStrengthReportingCriteria", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA, result, + mRILDefaultWorkSource); - try { - networkProxy.setSignalStrengthReportingCriteria(rr.mSerial, signalThresholdInfos); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "setSignalStrengthReportingCriteria", e); - } - } else { - riljLoge("setSignalStrengthReportingCriteria ignored on IRadio version less than 1.2"); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setSignalStrengthReportingCriteria", + () -> { + networkProxy.setSignalStrengthReportingCriteria(rr.mSerial, + signalThresholdInfos); + }); } @Override public void setLinkCapacityReportingCriteria(int hysteresisMs, int hysteresisDlKbps, int hysteresisUlKbps, int[] thresholdsDlKbps, int[] thresholdsUlKbps, int ran, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setLinkCapacityReportingCriteria", networkProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA, result, + mRILDefaultWorkSource); - try { - networkProxy.setLinkCapacityReportingCriteria(rr.mSerial, hysteresisMs, - hysteresisDlKbps, hysteresisUlKbps, thresholdsDlKbps, thresholdsUlKbps, - ran); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_NETWORK, "setLinkCapacityReportingCriteria", e); - } - } else { - riljLoge("setLinkCapacityReportingCriteria ignored on IRadio version less than 1.2"); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setLinkCapacityReportingCriteria", + () -> { + networkProxy.setLinkCapacityReportingCriteria(rr.mSerial, hysteresisMs, + hysteresisDlKbps, hysteresisUlKbps, thresholdsDlKbps, thresholdsUlKbps, + ran); + }); } @Override public void setSimCardPower(int state, Message result, WorkSource workSource) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (!simProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIM_CARD_POWER, result, - getDefaultWorkSourceIfInvalid(workSource)); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setSimCardPower", simProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " " + state); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIM_CARD_POWER, result, + getDefaultWorkSourceIfInvalid(workSource)); - try { - simProxy.setSimCardPower(rr.mSerial, state, result); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setSimCardPower", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + state); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setSimCardPower", () -> { + simProxy.setSimCardPower(rr.mSerial, state); + }); } @Override public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo, Message result) { Objects.requireNonNull(imsiEncryptionInfo, "ImsiEncryptionInfo cannot be null."); - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("setCarrierInfoForImsiEncryption", simProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - try { - simProxy.setCarrierInfoForImsiEncryption(rr.mSerial, imsiEncryptionInfo); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, - "setCarrierInfoForImsiEncryption", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setCarrierInfoForImsiEncryption: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, result, + mRILDefaultWorkSource); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "setCarrierInfoForImsiEncryption", () -> { + simProxy.setCarrierInfoForImsiEncryption(rr.mSerial, imsiEncryptionInfo); + }); } @Override public void startNattKeepalive(int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) { Objects.requireNonNull(packetData, "KeepaliveRequest cannot be null."); - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_START_KEEPALIVE, result, - mRILDefaultWorkSource); + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("startNattKeepalive", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_START_KEEPALIVE, result, mRILDefaultWorkSource); - try { - dataProxy.startKeepalive(rr.mSerial, contextId, packetData, intervalMillis, result); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "startNattKeepalive", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startNattKeepalive: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "startNattKeepalive", () -> { + dataProxy.startKeepalive(rr.mSerial, contextId, packetData, intervalMillis, result); + }); } @Override public void stopNattKeepalive(int sessionHandle, Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_STOP_KEEPALIVE, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - dataProxy.stopKeepalive(rr.mSerial, sessionHandle); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "stopNattKeepalive", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopNattKeepalive: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("stopNattKeepalive", dataProxy, result, RADIO_HAL_VERSION_1_4)) { + return; } - } - @Override - public void getIMEI(Message result) { - throw new RuntimeException("getIMEI not expected to be called"); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STOP_KEEPALIVE, result, mRILDefaultWorkSource); - @Override - public void getIMEISV(Message result) { - throw new RuntimeException("getIMEISV not expected to be called"); - } - - /** - * @deprecated - */ - @Deprecated - @Override - public void getLastPdpFailCause(Message result) { - throw new RuntimeException("getLastPdpFailCause not expected to be called"); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } - /** - * The preferred new alternative to getLastPdpFailCause - */ - @Override - public void getLastDataCallFailCause(Message result) { - throw new RuntimeException("getLastDataCallFailCause not expected to be called"); + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "stopNattKeepalive", () -> { + dataProxy.stopKeepalive(rr.mSerial, sessionHandle); + }); } /** @@ -4856,30 +4427,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void enableUiccApplications(boolean enable, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_UICC_APPLICATIONS, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("enableUiccApplications", simProxy, result, RADIO_HAL_VERSION_1_5)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " " + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_UICC_APPLICATIONS, result, + mRILDefaultWorkSource); - try { - simProxy.enableUiccApplications(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "enableUiccApplications", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "enableUiccApplications: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "enableUiccApplications", () -> { + simProxy.enableUiccApplications(rr.mSerial, enable); + }); } /** @@ -4889,31 +4452,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void areUiccApplicationsEnabled(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("areUiccApplicationsEnabled", simProxy, result, + RADIO_HAL_VERSION_1_5)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT, result, + mRILDefaultWorkSource); - try { - simProxy.areUiccApplicationsEnabled(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "areUiccApplicationsEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "areUiccApplicationsEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "areUiccApplicationsEnabled", () -> { + simProxy.areUiccApplicationsEnabled(rr.mSerial); + }); } /** @@ -4921,13 +4475,8 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public boolean canToggleUiccApplicationsEnablement() { - return !getRadioServiceProxy(RadioSimProxy.class, null).isEmpty() - && mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5); - } - - @Override - public void resetRadio(Message result) { - throw new RuntimeException("resetRadio not expected to be called"); + return canMakeRequest("canToggleUiccApplicationsEnablement", + getRadioServiceProxy(RadioSimProxy.class), null, RADIO_HAL_VERSION_1_5); } /** @@ -4935,22 +4484,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void handleCallSetupRequestFromSim(boolean accept, Message result) { - RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); - if (!voiceProxy.isEmpty()) { - RILRequest rr = obtainRequest(RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, - result, mRILDefaultWorkSource); + RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class); + if (!canMakeRequest("handleCallSetupRequestFromSim", voiceProxy, result, + RADIO_HAL_VERSION_1_4)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, + result, mRILDefaultWorkSource); - try { - voiceProxy.handleStkCallSetupRequestFromSim(rr.mSerial, accept); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_VOICE, "handleStkCallSetupRequestFromSim", e); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_VOICE, rr, "handleCallSetupRequestFromSim", () -> { + voiceProxy.handleStkCallSetupRequestFromSim(rr.mSerial, accept); + }); } /** @@ -4958,29 +4507,20 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getBarringInfo(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_BARRING_INFO, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getBarringInfo", networkProxy, result, RADIO_HAL_VERSION_1_5)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_BARRING_INFO, result, mRILDefaultWorkSource); - try { - networkProxy.getBarringInfo(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getBarringInfo", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getBarringInfo: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getBarringInfo", () -> { + networkProxy.getBarringInfo(rr.mSerial); + }); } /** @@ -4988,25 +4528,20 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void allocatePduSessionId(Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ALLOCATE_PDU_SESSION_ID, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("allocatePduSessionId", dataProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - try { - dataProxy.allocatePduSessionId(rr.mSerial); - } catch (RemoteException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "allocatePduSessionId", e); - } - } else { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + RILRequest rr = obtainRequest(RIL_REQUEST_ALLOCATE_PDU_SESSION_ID, result, + mRILDefaultWorkSource); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "allocatePduSessionId", () -> { + dataProxy.allocatePduSessionId(rr.mSerial); + }); } /** @@ -5014,25 +4549,20 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void releasePduSessionId(Message result, int pduSessionId) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_RELEASE_PDU_SESSION_ID, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("releasePduSessionId", dataProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - try { - dataProxy.releasePduSessionId(rr.mSerial, pduSessionId); - } catch (RemoteException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "releasePduSessionId", e); - } - } else { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + RILRequest rr = obtainRequest(RIL_REQUEST_RELEASE_PDU_SESSION_ID, result, + mRILDefaultWorkSource); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "releasePduSessionId", () -> { + dataProxy.releasePduSessionId(rr.mSerial, pduSessionId); + }); } /** @@ -5040,28 +4570,19 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void startHandover(Message result, int callId) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_START_HANDOVER, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("startHandover", dataProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - try { - dataProxy.startHandover(rr.mSerial, callId); - } catch (RemoteException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "startHandover", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startHandover: REQUEST_NOT_SUPPORTED"); - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + RILRequest rr = obtainRequest(RIL_REQUEST_START_HANDOVER, result, mRILDefaultWorkSource); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "startHandover", () -> { + dataProxy.startHandover(rr.mSerial, callId); + }); } /** @@ -5069,26 +4590,19 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void cancelHandover(Message result, int callId) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_HANDOVER, result, - mRILDefaultWorkSource); - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("cancelHandover", dataProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - try { - dataProxy.cancelHandover(rr.mSerial, callId); - } catch (RemoteException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "cancelHandover", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "cancelHandover: REQUEST_NOT_SUPPORTED"); - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_HANDOVER, result, mRILDefaultWorkSource); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "cancelHandover", () -> { + dataProxy.cancelHandover(rr.mSerial, callId); + }); } /** @@ -5096,115 +4610,79 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getSlicingConfig(Message result) { - RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); - if (dataProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLICING_CONFIG, result, - mRILDefaultWorkSource); + RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class); + if (!canMakeRequest("getSlicingConfig", dataProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLICING_CONFIG, result, + mRILDefaultWorkSource); - try { - dataProxy.getSlicingConfig(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "getSlicingConfig", e); - } - } else { - if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getSlicingConfig: REQUEST_NOT_SUPPORTED"); - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_DATA, rr, "getSlicingConfig", () -> { + dataProxy.getSlicingConfig(rr.mSerial); + }); } @Override public void getSimPhonebookRecords(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getSimPhonebookRecords", simProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS, result, + mRILDefaultWorkSource); - try { - simProxy.getSimPhonebookRecords(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getSimPhonebookRecords", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getSimPhonebookRecords: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getSimPhonebookRecords", () -> { + simProxy.getSimPhonebookRecords(rr.mSerial); + }); } @Override public void getSimPhonebookCapacity(Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("getSimPhonebookCapacity", simProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY, result, + mRILDefaultWorkSource); - try { - simProxy.getSimPhonebookCapacity(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getSimPhonebookCapacity", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getSimPhonebookCapacity: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "getSimPhonebookCapacity", () -> { + simProxy.getSimPhonebookCapacity(rr.mSerial); + }); } @Override public void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecord, Message result) { - RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); - if (simProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { - RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD, result, - mRILDefaultWorkSource); + RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class); + if (!canMakeRequest("updateSimPhonebookRecord", simProxy, result, RADIO_HAL_VERSION_1_6)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " with " + phonebookRecord.toString()); - } + RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD, result, + mRILDefaultWorkSource); - try { - simProxy.updateSimPhonebookRecords(rr.mSerial, phonebookRecord); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "updateSimPhonebookRecords", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "updateSimPhonebookRecords: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " with " + phonebookRecord.toString()); } + + radioServiceInvokeHelper(HAL_SERVICE_SIM, rr, "updateSimPhonebookRecord", () -> { + simProxy.updateSimPhonebookRecords(rr.mSerial, phonebookRecord); + }); } /** @@ -5216,31 +4694,20 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void setUsageSetting(Message result, /* @TelephonyManager.UsageSetting */ int usageSetting) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_USAGE_SETTING, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setUsageSetting", networkProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_USAGE_SETTING, result, mRILDefaultWorkSource); - try { - networkProxy.setUsageSetting(rr.mSerial, usageSetting); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setUsageSetting", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setUsageSetting: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setUsageSetting", () -> { + networkProxy.setUsageSetting(rr.mSerial, usageSetting); + }); } /** @@ -5250,62 +4717,40 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getUsageSetting(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_USAGE_SETTING, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("getUsageSetting", networkProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_GET_USAGE_SETTING, result, mRILDefaultWorkSource); - try { - networkProxy.getUsageSetting(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getUsageSetting", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getUsageSetting: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "getUsageSetting", () -> { + networkProxy.getUsageSetting(rr.mSerial); + }); } @Override public void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SRVCC_CALL_INFO, result, - mRILDefaultWorkSource); + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("setSrvccCallInfo", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SRVCC_CALL_INFO, result, + mRILDefaultWorkSource); - try { - imsProxy.setSrvccCallInfo(rr.mSerial, - RILUtils.convertToHalSrvccCall(srvccConnections)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "setSrvccCallInfo", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setSrvccCallInfo: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "setSrvccCallInfo", () -> { + imsProxy.setSrvccCallInfo(rr.mSerial, RILUtils.convertToHalSrvccCall(srvccConnections)); + }); } @Override @@ -5314,164 +4759,109 @@ public class RIL extends BaseCommands implements CommandsInterface { @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, @RegistrationManager.SuggestedAction int suggestedAction, int capabilities, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " state=" + state + ", radioTech=" + imsRadioTech - + ", suggested=" + suggestedAction + ", cap=" + capabilities); - } + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("updateImsRegistrationInfo", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - android.hardware.radio.ims.ImsRegistration registrationInfo = - new android.hardware.radio.ims.ImsRegistration(); - registrationInfo.regState = RILUtils.convertImsRegistrationState(state); - registrationInfo.accessNetworkType = RILUtils.convertImsRegistrationTech(imsRadioTech); - registrationInfo.suggestedAction = suggestedAction; - registrationInfo.capabilities = RILUtils.convertImsCapability(capabilities); + RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO, result, + mRILDefaultWorkSource); - try { - imsProxy.updateImsRegistrationInfo(rr.mSerial, registrationInfo); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "updateImsRegistrationInfo", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "updateImsRegistrationInfo: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " state=" + state + ", radioTech=" + imsRadioTech + + ", suggested=" + suggestedAction + ", cap=" + capabilities); } + + android.hardware.radio.ims.ImsRegistration registrationInfo = + new android.hardware.radio.ims.ImsRegistration(); + registrationInfo.regState = RILUtils.convertImsRegistrationState(state); + registrationInfo.accessNetworkType = RILUtils.convertImsRegistrationTech(imsRadioTech); + registrationInfo.suggestedAction = suggestedAction; + registrationInfo.capabilities = RILUtils.convertImsCapability(capabilities); + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "updateImsRegistrationInfo", () -> { + imsProxy.updateImsRegistrationInfo(rr.mSerial, registrationInfo); + }); } @Override - public void startImsTraffic(int token, - int trafficType, int accessNetworkType, int trafficDirection, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_START_IMS_TRAFFIC, result, - mRILDefaultWorkSource); + public void startImsTraffic(int token, int trafficType, int accessNetworkType, + int trafficDirection, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("startImsTraffic", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + "{" + token + ", " + trafficType + ", " - + accessNetworkType + ", " + trafficDirection + "}"); - } + RILRequest rr = obtainRequest(RIL_REQUEST_START_IMS_TRAFFIC, result, mRILDefaultWorkSource); - try { - imsProxy.startImsTraffic(rr.mSerial, token, - RILUtils.convertImsTrafficType(trafficType), accessNetworkType, - RILUtils.convertImsTrafficDirection(trafficDirection)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "startImsTraffic", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "startImsTraffic: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + "{" + token + ", " + trafficType + ", " + + accessNetworkType + ", " + trafficDirection + "}"); } + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "startImsTraffic", () -> { + imsProxy.startImsTraffic(rr.mSerial, token, RILUtils.convertImsTrafficType(trafficType), + accessNetworkType, RILUtils.convertImsTrafficDirection(trafficDirection)); + }); } @Override public void stopImsTraffic(int token, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_STOP_IMS_TRAFFIC, result, - mRILDefaultWorkSource); + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("stopImsTraffic", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + "{" + token + "}"); - } + RILRequest rr = obtainRequest(RIL_REQUEST_STOP_IMS_TRAFFIC, result, mRILDefaultWorkSource); - try { - imsProxy.stopImsTraffic(rr.mSerial, token); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "stopImsTraffic", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "stopImsTraffic: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + "{" + token + "}"); } + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "stopImsTraffic", () -> { + imsProxy.stopImsTraffic(rr.mSerial, token); + }); } @Override public void triggerEpsFallback(int reason, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EPS_FALLBACK, result, - mRILDefaultWorkSource); + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("triggerEpsFallback", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " reason=" + reason); - } + RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EPS_FALLBACK, result, + mRILDefaultWorkSource); - try { - imsProxy.triggerEpsFallback(rr.mSerial, reason); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "triggerEpsFallback", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "triggerEpsFallback: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " reason=" + reason); } + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "triggerEpsFallback", () -> { + imsProxy.triggerEpsFallback(rr.mSerial, reason); + }); } @Override - public void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, - Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SEND_ANBR_QUERY, result, - mRILDefaultWorkSource); + public void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("sendAnbrQuery", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_ANBR_QUERY, result, mRILDefaultWorkSource); - try { - imsProxy.sendAnbrQuery(rr.mSerial, mediaType, direction, bitsPerSecond); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "sendAnbrQuery", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "sendAnbrQuery: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "sendAnbrQuery", () -> { + imsProxy.sendAnbrQuery(rr.mSerial, mediaType, direction, bitsPerSecond); + }); } /** @@ -5479,32 +4869,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void setEmergencyMode(int emcMode, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_EMERGENCY_MODE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setEmergencyMode", networkProxy, result, RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " mode=" + EmergencyConstants.emergencyModeToString(emcMode)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_EMERGENCY_MODE, result, + mRILDefaultWorkSource); - try { - networkProxy.setEmergencyMode(rr.mSerial, emcMode); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setEmergencyMode", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setEmergencyMode: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " mode=" + EmergencyConstants.emergencyModeToString(emcMode)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setEmergencyMode", () -> { + networkProxy.setEmergencyMode(rr.mSerial, emcMode); + }); } /** @@ -5514,35 +4894,25 @@ public class RIL extends BaseCommands implements CommandsInterface { public void triggerEmergencyNetworkScan( @NonNull @AccessNetworkConstants.RadioAccessNetworkType int[] accessNetwork, @DomainSelectionService.EmergencyScanType int scanType, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("triggerEmergencyNetworkScan", networkProxy, result, + RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " networkType=" + RILUtils.accessNetworkTypesToString(accessNetwork) - + ", scanType=" + RILUtils.scanTypeToString(scanType)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN, result, + mRILDefaultWorkSource); - try { - networkProxy.triggerEmergencyNetworkScan(rr.mSerial, - RILUtils.convertEmergencyNetworkScanTrigger(accessNetwork, scanType)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "triggerEmergencyNetworkScan", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "triggerEmergencyNetworkScan: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " networkType=" + RILUtils.accessNetworkTypesToString(accessNetwork) + + ", scanType=" + RILUtils.scanTypeToString(scanType)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "triggerEmergencyNetworkScan", () -> { + networkProxy.triggerEmergencyNetworkScan(rr.mSerial, + RILUtils.convertEmergencyNetworkScanTrigger(accessNetwork, scanType)); + }); } /** @@ -5550,33 +4920,23 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void cancelEmergencyNetworkScan(boolean resetScan, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("cancelEmergencyNetworkScan", networkProxy, result, + RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " resetScan=" + resetScan); - } + RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN, result, + mRILDefaultWorkSource); - try { - networkProxy.cancelEmergencyNetworkScan(rr.mSerial, resetScan); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, - "cancelEmergencyNetworkScan", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "cancelEmergencyNetworkScan: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " resetScan=" + resetScan); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "cancelEmergencyNetworkScan", () -> { + networkProxy.cancelEmergencyNetworkScan(rr.mSerial, resetScan); + }); } /** @@ -5584,31 +4944,21 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void exitEmergencyMode(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_MODE, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("exitEmergencyMode", networkProxy, result, RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_MODE, result, + mRILDefaultWorkSource); - try { - networkProxy.exitEmergencyMode(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "exitEmergencyMode", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "exitEmergencyMode: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "exitEmergencyMode", () -> { + networkProxy.exitEmergencyMode(rr.mSerial); + }); } /** @@ -5619,32 +4969,23 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void setNullCipherAndIntegrityEnabled(boolean enabled, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setNullCipherAndIntegrityEnabled", networkProxy, result, + RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, + mRILDefaultWorkSource); - try { - networkProxy.setNullCipherAndIntegrityEnabled(rr.mSerial, enabled); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_NETWORK, "setNullCipherAndIntegrityEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setNullCipherAndIntegrityEnabled", + () -> { + networkProxy.setNullCipherAndIntegrityEnabled(rr.mSerial, enabled); + }); } /** @@ -5654,32 +4995,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isNullCipherAndIntegrityEnabled(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("isNullCipherAndIntegrityEnabled", networkProxy, result, + RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, + mRILDefaultWorkSource); - try { - networkProxy.isNullCipherAndIntegrityEnabled(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_NETWORK, "isNullCipherAndIntegrityEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "isNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "isNullCipherAndIntegrityEnabled", () -> { + networkProxy.isNullCipherAndIntegrityEnabled(rr.mSerial); + }); } /** @@ -5687,31 +5018,21 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void updateImsCallStatus(@NonNull List<ImsCallInfo> imsCallInfo, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_CALL_STATUS, result, - mRILDefaultWorkSource); + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class); + if (!canMakeRequest("updateImsCallStatus", imsProxy, result, RADIO_HAL_VERSION_2_0)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " " + imsCallInfo); - } - try { - imsProxy.updateImsCallStatus(rr.mSerial, RILUtils.convertImsCallInfo(imsCallInfo)); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "updateImsCallStatus", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "updateImsCallStatus: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_CALL_STATUS, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + imsCallInfo); } + radioServiceInvokeHelper(HAL_SERVICE_IMS, rr, "updateImsCallStatus", () -> { + imsProxy.updateImsCallStatus(rr.mSerial, RILUtils.convertImsCallInfo(imsCallInfo)); + }); } /** @@ -5719,32 +5040,22 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void setN1ModeEnabled(boolean enable, Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_N1_MODE_ENABLED, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("setN1ModeEnabled", networkProxy, result, RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " enable=" + enable); - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_N1_MODE_ENABLED, result, + mRILDefaultWorkSource); - try { - networkProxy.setN1ModeEnabled(rr.mSerial, enable); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setN1ModeEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setN1ModeEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable=" + enable); } + + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setN1ModeEnabled", () -> { + networkProxy.setN1ModeEnabled(rr.mSerial, enable); + }); } /** @@ -5752,306 +5063,137 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isN1ModeEnabled(Message result) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_IS_N1_MODE_ENABLED, result, - mRILDefaultWorkSource); + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest("isN1ModeEnabled", networkProxy, result, RADIO_HAL_VERSION_2_1)) { + return; + } - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } + RILRequest rr = obtainRequest(RIL_REQUEST_IS_N1_MODE_ENABLED, result, + mRILDefaultWorkSource); - try { - networkProxy.isN1ModeEnabled(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "isN1ModeEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "isN1ModeEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - /** - * Get feature capabilities supported by satellite. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatelliteCapabilities(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "isN1ModeEnabled", () -> { + networkProxy.isN1ModeEnabled(rr.mSerial); + }); } /** - * Turn satellite modem on/off. - * - * @param result Message that will be sent back to the requester - * @param on True for turning on. - * False for turning off. + * {@inheritDoc} */ @Override - public void setSatellitePower(Message result, boolean on) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + public void setCellularIdentifierTransparencyEnabled(boolean enable, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest( + "setCellularIdentifierTransparencyEnabled", + networkProxy, + result, + RADIO_HAL_VERSION_2_2)) { + return; } - } - /** - * Get satellite modem state. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatellitePowerState(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_CELLULAR_IDENTIFIER_DISCLOSED_ENABLED, result, + mRILDefaultWorkSource); - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatelliteProvisionState(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable=" + enable); } - } - /** - * Provision the subscription with a satellite provider. This is needed to register the - * subscription if the provider allows dynamic registration. - * - * @param result Message that will be sent back to the requester. - * @param imei IMEI of the SIM associated with the satellite modem. - * @param msisdn MSISDN of the SIM associated with the satellite modem. - * @param imsi IMSI of the SIM associated with the satellite modem. - * @param features List of features to be provisioned. - */ - @Override - public void provisionSatelliteService( - Message result, String imei, String msisdn, String imsi, int[] features) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + radioServiceInvokeHelper( + HAL_SERVICE_NETWORK, + rr, + "setCellularIdentifierTransparencyEnabled", + () -> { + networkProxy.setCellularIdentifierTransparencyEnabled(rr.mSerial, enable); + }); } /** - * Add contacts that are allowed to be used for satellite communication. This is applicable for - * incoming messages as well. - * - * @param result Message that will be sent back to the requester. - * @param contacts List of allowed contacts to be added. + * {@inheritDoc} */ @Override - public void addAllowedSatelliteContacts(Message result, String[] contacts) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + public void isCellularIdentifierTransparencyEnabled(Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest( + "isCellularIdentifierTransparencyEnabled", + networkProxy, + result, + RADIO_HAL_VERSION_2_2)) { + return; } - } - /** - * Remove contacts that are allowed to be used for satellite communication. This is applicable - * for incoming messages as well. - * - * @param result Message that will be sent back to the requester. - * @param contacts List of allowed contacts to be removed. - */ - @Override - public void removeAllowedSatelliteContacts(Message result, String[] contacts) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_IS_CELLULAR_IDENTIFIER_DISCLOSED_ENABLED, result, + mRILDefaultWorkSource); - /** - * Send text messages. - * - * @param result Message that will be sent back to the requester. - * @param messages List of messages in text format to be sent. - * @param destination The recipient of the message. - * @param latitude The current latitude of the device. - * @param longitude The current longitude of the device. - */ - @Override - public void sendSatelliteMessages(Message result, String[] messages, String destination, - double latitude, double longitude) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - /** - * Get pending messages. - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void getPendingSatelliteMessages(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + radioServiceInvokeHelper( + HAL_SERVICE_NETWORK, + rr, + "isCellularIdentifierTransparencyEnabled", + () -> { + networkProxy.isCellularIdentifierTransparencyEnabled(rr.mSerial); + }); } - /** - * Get current satellite registration mode. - * - * @param result Message that will be sent back to the requester. + /** + * {@inheritDoc} */ @Override - public void getSatelliteMode(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + public void setSecurityAlgorithmsUpdatedEnabled(boolean enable, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest( + "setSecurityAlgorithmsUpdatedEnabled", + networkProxy, + result, + RADIO_HAL_VERSION_2_2)) { + return; } - } - /** - * Set the filter for what type of indication framework want to receive from modem. - * - * @param result Message that will be sent back to the requester. - * @param filterBitmask The filter bitmask identifying what type of indication framework want to - * receive from modem. - */ - @Override - public void setSatelliteIndicationFilter(Message result, int filterBitmask) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED, result, + mRILDefaultWorkSource); - /** - * Check whether satellite modem is supported by the device. - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void isSatelliteSupported(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable=" + enable); } - } - /** - * User started pointing to the satellite. Modem should continue to update the ponting input - * as user moves device. - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void startSendingSatellitePointingInfo(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + radioServiceInvokeHelper(HAL_SERVICE_NETWORK, rr, "setSecurityAlgorithmsUpdatedEnabled", + () -> { + networkProxy.setSecurityAlgorithmsUpdatedEnabled(rr.mSerial, enable); + }); } /** - * Stop pointing to satellite indications. - * - * @param result Message that will be sent back to the requester. + * {@inheritDoc} */ @Override - public void stopSendingSatellitePointingInfo(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + public void isSecurityAlgorithmsUpdatedEnabled(Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class); + if (!canMakeRequest( + "isSecurityAlgorithmsUpdatedEnabled", + networkProxy, + result, + RADIO_HAL_VERSION_2_2)) { + return; } - } - /** - * Get max text limit for messaging per message. - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void getMaxCharactersPerSatelliteTextMessage(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } + RILRequest rr = obtainRequest(RIL_REQUEST_IS_SECURITY_ALGORITHMS_UPDATED_ENABLED, result, + mRILDefaultWorkSource); - /** - * Get whether satellite communication is allowed for the current location - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); } - } - /** - * Get time for next visibility of satellite. - * - * @param result Message that will be sent back to the requester. - */ - @Override - public void getTimeForNextSatelliteVisibility(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + radioServiceInvokeHelper( + HAL_SERVICE_NETWORK, rr, "isSecurityAlgorithmsUpdatedEnabled", () -> { + networkProxy.isSecurityAlgorithmsUpdatedEnabled(rr.mSerial); + }); } //***** Private Methods @@ -6076,8 +5218,7 @@ public class RIL extends BaseCommands implements CommandsInterface { rr = mRequestList.get(serial); } if (rr == null) { - Rlog.w(RILJ_LOG_TAG, "processRequestAck: Unexpected solicited ack response! " - + "serial: " + serial); + riljLogw("processRequestAck: Unexpected solicited ack response! serial: " + serial); } else { decrementWakeLock(rr); if (RILJ_LOGD) { @@ -6135,7 +5276,7 @@ public class RIL extends BaseCommands implements CommandsInterface { rr = mRequestList.get(serial); } if (rr == null) { - Rlog.w(RILJ_LOG_TAG, "Unexpected solicited ack response! sn: " + serial); + riljLogw("Unexpected solicited ack response! sn: " + serial); } else { decrementWakeLock(rr); if (mRadioBugDetector != null) { @@ -6151,8 +5292,8 @@ public class RIL extends BaseCommands implements CommandsInterface { rr = findAndRemoveRequestFromList(serial); if (rr == null) { - Rlog.e(RILJ_LOG_TAG, "processResponse: Unexpected response! serial: " + serial - + " ,error: " + error); + riljLoge("processResponse: Unexpected response! serial: " + serial + + ", error: " + error); return null; } Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_NETWORK, "RIL", rr.mSerial); @@ -6213,12 +5354,12 @@ public class RIL extends BaseCommands implements CommandsInterface { } else { switch (rr.mRequest) { case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: - if (mTestingEmergencyCall.getAndSet(false)) { - if (mEmergencyCallbackModeRegistrant != null) { - riljLog("testing emergency call, notify ECM Registrants"); - mEmergencyCallbackModeRegistrant.notifyRegistrant(); + if (mTestingEmergencyCall.getAndSet(false)) { + if (mEmergencyCallbackModeRegistrant != null) { + riljLog("testing emergency call, notify ECM Registrants"); + mEmergencyCallbackModeRegistrant.notifyRegistrant(); + } } - } } } return rr; @@ -6232,7 +5373,7 @@ public class RIL extends BaseCommands implements CommandsInterface { * @param responseInfo RadioResponseInfo received in the callback * @param ret object to be returned to request sender */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public void processResponseDone(RILRequest rr, RadioResponseInfo responseInfo, Object ret) { processResponseDoneInternal(rr, responseInfo.error, responseInfo.type, ret); } @@ -6270,14 +5411,22 @@ public class RIL extends BaseCommands implements CommandsInterface { private void processResponseDoneInternal(RILRequest rr, int rilError, int responseType, Object ret) { if (rilError == 0) { - if (RILJ_LOGD) { - riljLog(rr.serialString() + "< " + RILUtils.requestToString(rr.mRequest) - + " " + retToString(rr.mRequest, ret)); + if (isLogOrTrace()) { + String logStr = rr.serialString() + "< " + RILUtils.requestToString(rr.mRequest) + + " " + retToString(rr.mRequest, ret); + if (RILJ_LOGD) { + riljLog(logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } } else { - if (RILJ_LOGD) { - riljLog(rr.serialString() + "< " + RILUtils.requestToString(rr.mRequest) - + " error " + rilError); + if (isLogOrTrace()) { + String logStr = rr.serialString() + "< " + RILUtils.requestToString(rr.mRequest) + + " error " + rilError; + if (RILJ_LOGD) { + riljLog(logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } rr.onError(rilError, ret); } @@ -6321,7 +5470,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); acquireWakeLock(rr, FOR_ACK_WAKELOCK); if (service == HAL_SERVICE_RADIO) { - IRadio radioProxy = getRadioProxy(null); + IRadio radioProxy = getRadioProxy(); if (radioProxy != null) { try { radioProxy.responseAcknowledgement(); @@ -6330,10 +5479,10 @@ public class RIL extends BaseCommands implements CommandsInterface { riljLoge("sendAck: " + e); } } else { - Rlog.e(RILJ_LOG_TAG, "Error trying to send ack, radioProxy = null"); + riljLoge("Error trying to send ack, radioProxy = null"); } } else { - RadioServiceProxy serviceProxy = getRadioServiceProxy(service, null); + RadioServiceProxy serviceProxy = getRadioServiceProxy(service); if (!serviceProxy.isEmpty()) { try { serviceProxy.responseAcknowledgement(); @@ -6342,7 +5491,7 @@ public class RIL extends BaseCommands implements CommandsInterface { riljLoge("sendAck: " + e); } } else { - Rlog.e(RILJ_LOG_TAG, "Error trying to send ack, serviceProxy is empty"); + riljLoge("Error trying to send ack, serviceProxy is empty"); } } rr.release(); @@ -6369,11 +5518,11 @@ public class RIL extends BaseCommands implements CommandsInterface { private void acquireWakeLock(RILRequest rr, int wakeLockType) { synchronized (rr) { if (rr.mWakeLockType != INVALID_WAKELOCK) { - Rlog.d(RILJ_LOG_TAG, "Failed to aquire wakelock for " + rr.serialString()); + riljLog("Failed to acquire wakelock for " + rr.serialString()); return; } - switch(wakeLockType) { + switch (wakeLockType) { case FOR_WAKELOCK: synchronized (mWakeLock) { mWakeLock.acquire(); @@ -6405,7 +5554,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } break; default: //WTF - Rlog.w(RILJ_LOG_TAG, "Acquiring Invalid Wakelock type " + wakeLockType); + riljLogw("Acquiring Invalid Wakelock type " + wakeLockType); return; } rr.mWakeLockType = wakeLockType; @@ -6459,7 +5608,7 @@ public class RIL extends BaseCommands implements CommandsInterface { case INVALID_WAKELOCK: break; default: - Rlog.w(RILJ_LOG_TAG, "Decrementing Invalid Wakelock type " + rr.mWakeLockType); + riljLogw("Decrementing Invalid Wakelock type " + rr.mWakeLockType); } rr.mWakeLockType = INVALID_WAKELOCK; } @@ -6470,8 +5619,7 @@ public class RIL extends BaseCommands implements CommandsInterface { if (wakeLockType == FOR_WAKELOCK) { synchronized (mWakeLock) { if (mWakeLockCount == 0 && !mWakeLock.isHeld()) return false; - Rlog.d(RILJ_LOG_TAG, "NOTE: mWakeLockCount is " + mWakeLockCount - + " at time of clearing"); + riljLog("NOTE: mWakeLockCount is " + mWakeLockCount + " at time of clearing"); mWakeLockCount = 0; mWakeLock.release(); mClientWakelockTracker.stopTrackingAll(); @@ -6498,15 +5646,14 @@ public class RIL extends BaseCommands implements CommandsInterface { synchronized (mRequestList) { int count = mRequestList.size(); if (RILJ_LOGD && loggable) { - Rlog.d(RILJ_LOG_TAG, "clearRequestList " + " mWakeLockCount=" - + mWakeLockCount + " mRequestList=" + count); + riljLog("clearRequestList " + " mWakeLockCount=" + mWakeLockCount + + " mRequestList=" + count); } for (int i = 0; i < count; i++) { rr = mRequestList.valueAt(i); if (RILJ_LOGD && loggable) { - Rlog.d(RILJ_LOG_TAG, i + ": [" + rr.mSerial + "] " - + RILUtils.requestToString(rr.mRequest)); + riljLog(i + ": [" + rr.mSerial + "] " + RILUtils.requestToString(rr.mRequest)); } rr.onError(error, null); decrementWakeLock(rr); @@ -6571,6 +5718,7 @@ public class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_GET_IMEISV: case RIL_REQUEST_SIM_OPEN_CHANNEL: case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL: + case RIL_REQUEST_DEVICE_IMEI: if (!RILJ_LOGV) { // If not versbose logging just return and don't display IMSI and IMEI, IMEISV @@ -6763,6 +5911,13 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + void notifyRegistrantsImeiMappingChanged(ImeiInfo imeiInfo) { + if (mImeiInfoRegistrants != null) { + mImeiInfoRegistrants.notifyRegistrants( + new AsyncResult(null, imeiInfo, null)); + } + } + @UnsupportedAppUsage void riljLog(String msg) { Rlog.d(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]")); @@ -6776,18 +5931,22 @@ public class RIL extends BaseCommands implements CommandsInterface { Rlog.v(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]")); } + void riljLogw(String msg) { + Rlog.w(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]")); + } + boolean isLogOrTrace() { - return RIL.RILJ_LOGD || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); + return RILJ_LOGD || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); } boolean isLogvOrTrace() { - return RIL.RILJ_LOGV || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); + return RILJ_LOGV || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); } @UnsupportedAppUsage void unsljLog(int response) { String logStr = RILUtils.responseToString(response); - if (RIL.RILJ_LOGD) { + if (RILJ_LOGD) { riljLog("[UNSL]< " + logStr); } Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); @@ -6796,7 +5955,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @UnsupportedAppUsage void unsljLogMore(int response, String more) { String logStr = RILUtils.responseToString(response) + " " + more; - if (RIL.RILJ_LOGD) { + if (RILJ_LOGD) { riljLog("[UNSL]< " + logStr); } Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); @@ -6805,7 +5964,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @UnsupportedAppUsage void unsljLogRet(int response, Object ret) { String logStr = RILUtils.responseToString(response) + " " + retToString(response, ret); - if (RIL.RILJ_LOGD) { + if (RILJ_LOGD) { riljLog("[UNSL]< " + logStr); } Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); @@ -6814,7 +5973,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @UnsupportedAppUsage void unsljLogvRet(int response, Object ret) { String logStr = RILUtils.responseToString(response) + " " + retToString(response, ret); - if (RIL.RILJ_LOGV) { + if (RILJ_LOGV) { riljLogv("[UNSL]< " + logStr); } Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); @@ -6867,58 +6026,6 @@ public class RIL extends BaseCommands implements CommandsInterface { return mClientWakelockTracker.getClientRequestStats(); } - /** - * Fixup for SignalStrength 1.0 to Assume GSM to WCDMA when - * The current RAT type is one of the UMTS RATs. - * @param signalStrength the initial signal strength - * @return a new SignalStrength if RAT is UMTS or existing SignalStrength - */ - public SignalStrength fixupSignalStrength10(SignalStrength signalStrength) { - List<CellSignalStrengthGsm> gsmList = signalStrength.getCellSignalStrengths( - CellSignalStrengthGsm.class); - // If GSM is not the primary type, then bail out; no fixup needed. - if (gsmList.isEmpty() || !gsmList.get(0).isValid()) { - return signalStrength; - } - - CellSignalStrengthGsm gsmStrength = gsmList.get(0); - - // Use the voice RAT which is a guarantee in GSM and UMTS - int voiceRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - Phone phone = PhoneFactory.getPhone(mPhoneId); - if (phone != null) { - ServiceState ss = phone.getServiceState(); - if (ss != null) { - voiceRat = ss.getRilVoiceRadioTechnology(); - } - } - switch (voiceRat) { - case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: /* fallthrough */ - case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: /* fallthrough */ - case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: /* fallthrough */ - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: /* fallthrough */ - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: /* fallthrough */ - break; - default: - // If we are not currently on WCDMA/HSPA, then we don't need to do a fixup. - return signalStrength; - } - - // The service state reports WCDMA, and the SignalStrength is reported for GSM, so at this - // point we take an educated guess that the GSM SignalStrength report is actually for - // WCDMA. Also, if we are in WCDMA/GSM we can safely assume that there are no other valid - // signal strength reports (no SRLTE, which is the only supported case in HAL 1.0). - // Thus, we just construct a new SignalStrength and migrate RSSI and BER from the - // GSM report to the WCDMA report, leaving everything else empty. - return new SignalStrength( - new CellSignalStrengthCdma(), new CellSignalStrengthGsm(), - new CellSignalStrengthWcdma(gsmStrength.getRssi(), - gsmStrength.getBitErrorRate(), - CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE), - new CellSignalStrengthTdscdma(), new CellSignalStrengthLte(), - new CellSignalStrengthNr()); - } - void notifyBarringInfoChanged(@NonNull BarringInfo barringInfo) { mLastBarringInfo = barringInfo; mBarringInfoChangedRegistrants.notifyRegistrants(new AsyncResult(null, barringInfo, null)); @@ -6951,6 +6058,7 @@ public class RIL extends BaseCommands implements CommandsInterface { switch (interfaceVersion) { case 1: return RADIO_HAL_VERSION_2_0; case 2: return RADIO_HAL_VERSION_2_1; + case 3: return RADIO_HAL_VERSION_2_2; default: return RADIO_HAL_VERSION_UNKNOWN; } } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index ae8d033939..94f2e962ee 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -91,6 +91,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HARDWA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEI; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEISV; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_LOCATION_PRIVACY_SETTING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MODEM_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS; @@ -164,6 +165,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_EMERGE import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_FACILITY_LOCK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_INITIAL_ATTACH_APN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOCATION_PRIVACY_SETTING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOCATION_UPDATES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_MUTE; @@ -239,6 +241,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ENTER_EMERGE import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ICC_SLOT_STATUS; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_STATUS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; @@ -320,6 +323,7 @@ import android.telephony.CellSignalStrengthLte; import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.ClosedSubscriberGroupInfo; import android.telephony.DomainSelectionService; import android.telephony.EmergencyRegResult; @@ -357,7 +361,6 @@ import android.telephony.ims.feature.ConnectionFailureInfo; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; -import android.telephony.satellite.SatelliteManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.SparseArray; @@ -874,41 +877,6 @@ public class RILUtils { } /** - * Convert to DataProfileInfo defined in radio/1.0/types.hal - * @param dp Data profile - * @return The converted DataProfileInfo - */ - public static android.hardware.radio.V1_0.DataProfileInfo convertToHalDataProfile10( - DataProfile dp) { - android.hardware.radio.V1_0.DataProfileInfo dpi = - new android.hardware.radio.V1_0.DataProfileInfo(); - - dpi.profileId = dp.getProfileId(); - dpi.apn = dp.getApn(); - dpi.protocol = ApnSetting.getProtocolStringFromInt(dp.getProtocolType()); - dpi.roamingProtocol = ApnSetting.getProtocolStringFromInt(dp.getRoamingProtocolType()); - dpi.authType = dp.getAuthType(); - dpi.user = TextUtils.emptyIfNull(dp.getUserName()); - dpi.password = TextUtils.emptyIfNull(dp.getPassword()); - dpi.type = dp.getType(); - dpi.maxConnsTime = dp.getMaxConnectionsTime(); - dpi.maxConns = dp.getMaxConnections(); - dpi.waitTime = dp.getWaitTime(); - dpi.enabled = dp.isEnabled(); - dpi.supportedApnTypesBitmap = dp.getSupportedApnTypesBitmask(); - // Shift by 1 bit due to the discrepancy between - // android.hardware.radio.V1_0.RadioAccessFamily and the bitmask version of - // ServiceState.RIL_RADIO_TECHNOLOGY_XXXX. - dpi.bearerBitmap = ServiceState.convertNetworkTypeBitmaskToBearerBitmask( - dp.getBearerBitmask()) << 1; - dpi.mtu = dp.getMtuV4(); - dpi.mvnoType = android.hardware.radio.V1_0.MvnoType.NONE; - dpi.mvnoMatchData = ""; - - return dpi; - } - - /** * Convert to DataProfileInfo defined in radio/1.4/types.hal * @param dp Data profile * @return The converted DataProfileInfo @@ -990,8 +958,8 @@ public class RILUtils { * @param dp Data profile * @return The converted DataProfileInfo */ - public static android.hardware.radio.data.DataProfileInfo convertToHalDataProfile(@Nullable - DataProfile dp) { + public static android.hardware.radio.data.DataProfileInfo convertToHalDataProfile( + @Nullable DataProfile dp) { if (dp == null) return null; android.hardware.radio.data.DataProfileInfo dpi = new android.hardware.radio.data.DataProfileInfo(); @@ -1017,8 +985,11 @@ public class RILUtils { dpi.persistent = dp.isPersistent(); dpi.preferred = dp.isPreferred(); dpi.alwaysOn = false; + dpi.infrastructureBitmap = android.hardware.radio.data.DataProfileInfo + .INFRASTRUCTURE_CELLULAR; if (dp.getApnSetting() != null) { dpi.alwaysOn = dp.getApnSetting().isAlwaysOn(); + dpi.infrastructureBitmap = dp.getApnSetting().getInfrastructureBitmask(); } dpi.trafficDescriptor = convertToHalTrafficDescriptorAidl(dp.getTrafficDescriptor()); @@ -1056,6 +1027,7 @@ public class RILUtils { .setRoamingProtocol(dpi.roamingProtocol) .setUser(dpi.user) .setAlwaysOn(dpi.alwaysOn) + .setInfrastructureBitmask(dpi.infrastructureBitmap) .build(); TrafficDescriptor td; @@ -2198,21 +2170,15 @@ public class RILUtils { } /** - * Convert LceDataInfo defined in radio/1.0/types.hal and LinkCapacityEstimate defined in - * radio/1.2, 1.6/types.hal to a list of LinkCapacityEstimates - * @param lceObj LceDataInfo defined in radio/1.0/types.hal or LinkCapacityEstimate defined in - * radio/1.2, 1.6/types.hal + * Convert LinkCapacityEstimate defined in radio/1.2, 1.6/types.hal to + * a list of LinkCapacityEstimates + * @param lceObj LinkCapacityEstimate defined in radio/1.2, 1.6/types.hal * @return The converted list of LinkCapacityEstimates */ - public static List<LinkCapacityEstimate> convertHalLceData(Object lceObj) { + public static List<LinkCapacityEstimate> convertHalLinkCapacityEstimate(Object lceObj) { final List<LinkCapacityEstimate> lceList = new ArrayList<>(); if (lceObj == null) return lceList; - if (lceObj instanceof android.hardware.radio.V1_0.LceDataInfo) { - android.hardware.radio.V1_0.LceDataInfo lce = - (android.hardware.radio.V1_0.LceDataInfo) lceObj; - lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED, - lce.lastHopCapacityKbps, LinkCapacityEstimate.INVALID)); - } else if (lceObj instanceof android.hardware.radio.V1_2.LinkCapacityEstimate) { + if (lceObj instanceof android.hardware.radio.V1_2.LinkCapacityEstimate) { android.hardware.radio.V1_2.LinkCapacityEstimate lce = (android.hardware.radio.V1_2.LinkCapacityEstimate) lceObj; lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED, @@ -2241,25 +2207,12 @@ public class RILUtils { } /** - * Convert LceDataInfo defined in LceDataInfo.aidl to a list of LinkCapacityEstimates - * @param lce LceDataInfo defined in LceDataInfo.aidl - * @return The converted list of LinkCapacityEstimates - */ - public static List<LinkCapacityEstimate> convertHalLceData( - android.hardware.radio.network.LceDataInfo lce) { - final List<LinkCapacityEstimate> lceList = new ArrayList<>(); - lceList.add(new LinkCapacityEstimate(LinkCapacityEstimate.LCE_TYPE_COMBINED, - lce.lastHopCapacityKbps, LinkCapacityEstimate.INVALID)); - return lceList; - } - - /** * Convert LinkCapacityEstimate defined in LinkCapacityEstimate.aidl to a list of * LinkCapacityEstimates * @param lce LinkCapacityEstimate defined in LinkCapacityEstimate.aidl * @return The converted list of LinkCapacityEstimates */ - public static List<LinkCapacityEstimate> convertHalLceData( + public static List<LinkCapacityEstimate> convertHalLinkCapacityEstimate( android.hardware.radio.network.LinkCapacityEstimate lce) { final List<LinkCapacityEstimate> lceList = new ArrayList<>(); int primaryDownlinkCapacityKbps = lce.downlinkCapacityKbps; @@ -2283,9 +2236,9 @@ public class RILUtils { /** - * Convert a list of CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal to a list of + * Convert a list of CellInfo defined in radio/1.4, 1.5, 1.6/types.hal to a list of * CellInfos - * @param records List of CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal + * @param records List of CellInfo defined in radio/1.4, 1.5, 1.6/types.hal * @return The converted list of CellInfos */ public static ArrayList<CellInfo> convertHalCellInfoList(ArrayList<Object> records) { @@ -2315,8 +2268,8 @@ public class RILUtils { } /** - * Convert a CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal to CellInfo - * @param cellInfo CellInfo defined in radio/1.0, 1.2, 1.4, 1.5, 1.6/types.hal + * Convert a CellInfo defined in radio/1.4, 1.5, 1.6/types.hal to CellInfo + * @param cellInfo CellInfo defined in radio/1.4, 1.5, 1.6/types.hal * @param nanotime time the CellInfo was created * @return The converted CellInfo */ @@ -2338,87 +2291,7 @@ public class RILUtils { CellSignalStrengthTdscdma tdscdmaSs = null; CellIdentityNr nrCi = null; CellSignalStrengthNr nrSs = null; - if (cellInfo instanceof android.hardware.radio.V1_0.CellInfo) { - final android.hardware.radio.V1_0.CellInfo record = - (android.hardware.radio.V1_0.CellInfo) cellInfo; - connectionStatus = CellInfo.CONNECTION_UNKNOWN; - registered = record.registered; - switch (record.cellInfoType) { - case android.hardware.radio.V1_0.CellInfoType.GSM: - type = CellInfo.TYPE_GSM; - android.hardware.radio.V1_0.CellInfoGsm gsm = record.gsm.get(0); - gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm); - gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm); - break; - case android.hardware.radio.V1_0.CellInfoType.CDMA: - type = CellInfo.TYPE_CDMA; - android.hardware.radio.V1_0.CellInfoCdma cdma = record.cdma.get(0); - cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma); - cdmaSs = convertHalCdmaSignalStrength( - cdma.signalStrengthCdma, cdma.signalStrengthEvdo); - break; - case android.hardware.radio.V1_0.CellInfoType.LTE: - type = CellInfo.TYPE_LTE; - android.hardware.radio.V1_0.CellInfoLte lte = record.lte.get(0); - lteCi = convertHalCellIdentityLte(lte.cellIdentityLte); - lteSs = convertHalLteSignalStrength(lte.signalStrengthLte); - lteCc = new CellConfigLte(); - break; - case android.hardware.radio.V1_0.CellInfoType.WCDMA: - type = CellInfo.TYPE_WCDMA; - android.hardware.radio.V1_0.CellInfoWcdma wcdma = record.wcdma.get(0); - wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma); - wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma); - break; - case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: - type = CellInfo.TYPE_TDSCDMA; - android.hardware.radio.V1_0.CellInfoTdscdma tdscdma = record.tdscdma.get(0); - tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma); - tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma); - break; - default: return null; - } - } else if (cellInfo instanceof android.hardware.radio.V1_2.CellInfo) { - final android.hardware.radio.V1_2.CellInfo record = - (android.hardware.radio.V1_2.CellInfo) cellInfo; - connectionStatus = record.connectionStatus; - registered = record.registered; - switch(record.cellInfoType) { - case android.hardware.radio.V1_0.CellInfoType.GSM: - type = CellInfo.TYPE_GSM; - android.hardware.radio.V1_2.CellInfoGsm gsm = record.gsm.get(0); - gsmCi = convertHalCellIdentityGsm(gsm.cellIdentityGsm); - gsmSs = convertHalGsmSignalStrength(gsm.signalStrengthGsm); - break; - case android.hardware.radio.V1_0.CellInfoType.CDMA: - type = CellInfo.TYPE_CDMA; - android.hardware.radio.V1_2.CellInfoCdma cdma = record.cdma.get(0); - cdmaCi = convertHalCellIdentityCdma(cdma.cellIdentityCdma); - cdmaSs = convertHalCdmaSignalStrength( - cdma.signalStrengthCdma, cdma.signalStrengthEvdo); - break; - case android.hardware.radio.V1_0.CellInfoType.LTE: - type = CellInfo.TYPE_LTE; - android.hardware.radio.V1_2.CellInfoLte lte = record.lte.get(0); - lteCi = convertHalCellIdentityLte(lte.cellIdentityLte); - lteSs = convertHalLteSignalStrength(lte.signalStrengthLte); - lteCc = new CellConfigLte(); - break; - case android.hardware.radio.V1_0.CellInfoType.WCDMA: - type = CellInfo.TYPE_WCDMA; - android.hardware.radio.V1_2.CellInfoWcdma wcdma = record.wcdma.get(0); - wcdmaCi = convertHalCellIdentityWcdma(wcdma.cellIdentityWcdma); - wcdmaSs = convertHalWcdmaSignalStrength(wcdma.signalStrengthWcdma); - break; - case android.hardware.radio.V1_0.CellInfoType.TD_SCDMA: - type = CellInfo.TYPE_TDSCDMA; - android.hardware.radio.V1_2.CellInfoTdscdma tdscdma = record.tdscdma.get(0); - tdscdmaCi = convertHalCellIdentityTdscdma(tdscdma.cellIdentityTdscdma); - tdscdmaSs = convertHalTdscdmaSignalStrength(tdscdma.signalStrengthTdscdma); - break; - default: return null; - } - } else if (cellInfo instanceof android.hardware.radio.V1_4.CellInfo) { + if (cellInfo instanceof android.hardware.radio.V1_4.CellInfo) { final android.hardware.radio.V1_4.CellInfo record = (android.hardware.radio.V1_4.CellInfo) cellInfo; connectionStatus = record.connectionStatus; @@ -2648,43 +2521,13 @@ public class RILUtils { } /** - * Convert a CellIdentity defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentity - * @param halCi CellIdentity defined in radio/1.0, 1.2, 1.5/types.hal + * Convert a CellIdentity defined in radio/1.2, 1.5/types.hal to CellIdentity + * @param halCi CellIdentity defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentity */ public static CellIdentity convertHalCellIdentity(Object halCi) { if (halCi == null) return null; - if (halCi instanceof android.hardware.radio.V1_0.CellIdentity) { - android.hardware.radio.V1_0.CellIdentity ci = - (android.hardware.radio.V1_0.CellIdentity) halCi; - switch (ci.cellInfoType) { - case CellInfo.TYPE_GSM: - if (ci.cellIdentityGsm.size() == 1) { - return convertHalCellIdentityGsm(ci.cellIdentityGsm.get(0)); - } - break; - case CellInfo.TYPE_CDMA: - if (ci.cellIdentityCdma.size() == 1) { - return convertHalCellIdentityCdma(ci.cellIdentityCdma.get(0)); - } - break; - case CellInfo.TYPE_LTE: - if (ci.cellIdentityLte.size() == 1) { - return convertHalCellIdentityLte(ci.cellIdentityLte.get(0)); - } - break; - case CellInfo.TYPE_WCDMA: - if (ci.cellIdentityWcdma.size() == 1) { - return convertHalCellIdentityWcdma(ci.cellIdentityWcdma.get(0)); - } - break; - case CellInfo.TYPE_TDSCDMA: - if (ci.cellIdentityTdscdma.size() == 1) { - return convertHalCellIdentityTdscdma(ci.cellIdentityTdscdma.get(0)); - } - break; - } - } else if (halCi instanceof android.hardware.radio.V1_2.CellIdentity) { + if (halCi instanceof android.hardware.radio.V1_2.CellIdentity) { android.hardware.radio.V1_2.CellIdentity ci = (android.hardware.radio.V1_2.CellIdentity) halCi; switch (ci.cellInfoType) { @@ -2761,19 +2604,13 @@ public class RILUtils { } /** - * Convert a CellIdentityGsm defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityGsm - * @param gsm CellIdentityGsm defined in radio/1.0, 1.2, 1.5/types.hal + * Convert a CellIdentityGsm defined in radio/1.2, 1.5/types.hal to CellIdentityGsm + * @param gsm CellIdentityGsm defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentityGsm */ public static CellIdentityGsm convertHalCellIdentityGsm(Object gsm) { if (gsm == null) return null; - if (gsm instanceof android.hardware.radio.V1_0.CellIdentityGsm) { - android.hardware.radio.V1_0.CellIdentityGsm ci = - (android.hardware.radio.V1_0.CellIdentityGsm) gsm; - return new CellIdentityGsm(ci.lac, ci.cid, ci.arfcn, - ci.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : ci.bsic, ci.mcc, ci.mnc, "", "", - new ArraySet<>()); - } else if (gsm instanceof android.hardware.radio.V1_2.CellIdentityGsm) { + if (gsm instanceof android.hardware.radio.V1_2.CellIdentityGsm) { android.hardware.radio.V1_2.CellIdentityGsm ci = (android.hardware.radio.V1_2.CellIdentityGsm) gsm; return new CellIdentityGsm(ci.base.lac, ci.base.cid, ci.base.arfcn, @@ -2806,18 +2643,13 @@ public class RILUtils { } /** - * Convert a CellIdentityCdma defined in radio/1.0, 1.2/types.hal to CellIdentityCdma - * @param cdma CellIdentityCdma defined in radio/1.0, 1.2/types.hal + * Convert a CellIdentityCdma defined in radio/1.2/types.hal to CellIdentityCdma + * @param cdma CellIdentityCdma defined in radio/1.2/types.hal * @return The converted CellIdentityCdma */ public static CellIdentityCdma convertHalCellIdentityCdma(Object cdma) { if (cdma == null) return null; - if (cdma instanceof android.hardware.radio.V1_0.CellIdentityCdma) { - android.hardware.radio.V1_0.CellIdentityCdma ci = - (android.hardware.radio.V1_0.CellIdentityCdma) cdma; - return new CellIdentityCdma(ci.networkId, ci.systemId, ci.baseStationId, ci.longitude, - ci.latitude, "", ""); - } else if (cdma instanceof android.hardware.radio.V1_2.CellIdentityCdma) { + if (cdma instanceof android.hardware.radio.V1_2.CellIdentityCdma) { android.hardware.radio.V1_2.CellIdentityCdma ci = (android.hardware.radio.V1_2.CellIdentityCdma) cdma; return new CellIdentityCdma(ci.base.networkId, ci.base.systemId, ci.base.baseStationId, @@ -2840,18 +2672,13 @@ public class RILUtils { } /** - * Convert a CellIdentityLte defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityLte - * @param lte CellIdentityLte defined in radio/1.0, 1.2, 1.5/types.hal + * Convert a CellIdentityLte defined in radio/1.2, 1.5/types.hal to CellIdentityLte + * @param lte CellIdentityLte defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentityLte */ public static CellIdentityLte convertHalCellIdentityLte(Object lte) { if (lte == null) return null; - if (lte instanceof android.hardware.radio.V1_0.CellIdentityLte) { - android.hardware.radio.V1_0.CellIdentityLte ci = - (android.hardware.radio.V1_0.CellIdentityLte) lte; - return new CellIdentityLte(ci.ci, ci.pci, ci.tac, ci.earfcn, new int[] {}, - CellInfo.UNAVAILABLE, ci.mcc, ci.mnc, "", "", new ArraySet<>(), null); - } else if (lte instanceof android.hardware.radio.V1_2.CellIdentityLte) { + if (lte instanceof android.hardware.radio.V1_2.CellIdentityLte) { android.hardware.radio.V1_2.CellIdentityLte ci = (android.hardware.radio.V1_2.CellIdentityLte) lte; return new CellIdentityLte(ci.base.ci, ci.base.pci, ci.base.tac, ci.base.earfcn, @@ -2885,18 +2712,13 @@ public class RILUtils { } /** - * Convert a CellIdentityWcdma defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityWcdma - * @param wcdma CellIdentityWcdma defined in radio/1.0, 1.2, 1.5/types.hal + * Convert a CellIdentityWcdma defined in radio/1.2, 1.5/types.hal to CellIdentityWcdma + * @param wcdma CellIdentityWcdma defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentityWcdma */ public static CellIdentityWcdma convertHalCellIdentityWcdma(Object wcdma) { if (wcdma == null) return null; - if (wcdma instanceof android.hardware.radio.V1_0.CellIdentityWcdma) { - android.hardware.radio.V1_0.CellIdentityWcdma ci = - (android.hardware.radio.V1_0.CellIdentityWcdma) wcdma; - return new CellIdentityWcdma(ci.lac, ci.cid, ci.psc, ci.uarfcn, ci.mcc, ci.mnc, "", "", - new ArraySet<>(), null); - } else if (wcdma instanceof android.hardware.radio.V1_2.CellIdentityWcdma) { + if (wcdma instanceof android.hardware.radio.V1_2.CellIdentityWcdma) { android.hardware.radio.V1_2.CellIdentityWcdma ci = (android.hardware.radio.V1_2.CellIdentityWcdma) wcdma; return new CellIdentityWcdma(ci.base.lac, ci.base.cid, ci.base.psc, ci.base.uarfcn, @@ -2928,18 +2750,13 @@ public class RILUtils { } /** - * Convert a CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal to CellIdentityTdscdma - * @param tdscdma CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal + * Convert a CellIdentityTdscdma defined in radio/1.2, 1.5/types.hal to CellIdentityTdscdma + * @param tdscdma CellIdentityTdscdma defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentityTdscdma */ public static CellIdentityTdscdma convertHalCellIdentityTdscdma(Object tdscdma) { if (tdscdma == null) return null; - if (tdscdma instanceof android.hardware.radio.V1_0.CellIdentityTdscdma) { - android.hardware.radio.V1_0.CellIdentityTdscdma ci = - (android.hardware.radio.V1_0.CellIdentityTdscdma) tdscdma; - return new CellIdentityTdscdma(ci.mcc, ci.mnc, ci.lac, ci.cid, ci.cpid, - CellInfo.UNAVAILABLE, "", "", Collections.emptyList(), null); - } else if (tdscdma instanceof android.hardware.radio.V1_2.CellIdentityTdscdma) { + if (tdscdma instanceof android.hardware.radio.V1_2.CellIdentityTdscdma) { android.hardware.radio.V1_2.CellIdentityTdscdma ci = (android.hardware.radio.V1_2.CellIdentityTdscdma) tdscdma; return new CellIdentityTdscdma(ci.base.mcc, ci.base.mnc, ci.base.lac, ci.base.cid, @@ -2959,7 +2776,7 @@ public class RILUtils { /** * Convert a CellIdentityTdscdma defined in CellIdentityTdscdma.aidl to CellIdentityTdscdma - * @param cid CellIdentityTdscdma defined in radio/1.0, 1.2, 1.5/types.hal + * @param cid CellIdentityTdscdma defined in radio/1.2, 1.5/types.hal * @return The converted CellIdentityTdscdma */ public static CellIdentityTdscdma convertHalCellIdentityTdscdma( @@ -3008,31 +2825,13 @@ public class RILUtils { } /** - * Convert a SignalStrength defined in radio/1.0, 1.2, 1.4, 1.6/types.hal to SignalStrength - * @param ss SignalStrength defined in radio/1.0, 1.2, 1.4, 1.6/types.hal + * Convert a SignalStrength defined in radio/1.4, 1.6/types.hal to SignalStrength + * @param ss SignalStrength defined in radio/1.4, 1.6/types.hal * @return The converted SignalStrength */ public static SignalStrength convertHalSignalStrength(Object ss) { if (ss == null) return null; - if (ss instanceof android.hardware.radio.V1_0.SignalStrength) { - android.hardware.radio.V1_0.SignalStrength signalStrength = - (android.hardware.radio.V1_0.SignalStrength) ss; - return new SignalStrength( - convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo), - convertHalGsmSignalStrength(signalStrength.gw), new CellSignalStrengthWcdma(), - convertHalTdscdmaSignalStrength(signalStrength.tdScdma), - convertHalLteSignalStrength(signalStrength.lte), - new CellSignalStrengthNr()); - } else if (ss instanceof android.hardware.radio.V1_2.SignalStrength) { - android.hardware.radio.V1_2.SignalStrength signalStrength = - (android.hardware.radio.V1_2.SignalStrength) ss; - return new SignalStrength( - convertHalCdmaSignalStrength(signalStrength.cdma, signalStrength.evdo), - convertHalGsmSignalStrength(signalStrength.gsm), - convertHalWcdmaSignalStrength(signalStrength.wcdma), - convertHalTdscdmaSignalStrength(signalStrength.tdScdma), - convertHalLteSignalStrength(signalStrength.lte), new CellSignalStrengthNr()); - } else if (ss instanceof android.hardware.radio.V1_4.SignalStrength) { + if (ss instanceof android.hardware.radio.V1_4.SignalStrength) { android.hardware.radio.V1_4.SignalStrength signalStrength = (android.hardware.radio.V1_4.SignalStrength) ss; return new SignalStrength( @@ -3180,29 +2979,19 @@ public class RILUtils { } /** - * Convert a WcdmaSignalStrength defined in radio/1.0, 1.2/types.hal to CellSignalStrengthWcdma - * @param wcdma WcdmaSignalStrength defined in radio/1.0, 1.2/types.hal + * Convert a WcdmaSignalStrength defined in radio/1.2/types.hal to CellSignalStrengthWcdma + * @param wcdma WcdmaSignalStrength defined in radio/1.2/types.hal * @return The converted CellSignalStrengthWcdma */ public static CellSignalStrengthWcdma convertHalWcdmaSignalStrength(Object wcdma) { if (wcdma == null) return null; - CellSignalStrengthWcdma ret = null; - if (wcdma instanceof android.hardware.radio.V1_0.WcdmaSignalStrength) { - android.hardware.radio.V1_0.WcdmaSignalStrength ss = - (android.hardware.radio.V1_0.WcdmaSignalStrength) wcdma; - ret = new CellSignalStrengthWcdma( - CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate, - CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE); - } else if (wcdma instanceof android.hardware.radio.V1_2.WcdmaSignalStrength) { - android.hardware.radio.V1_2.WcdmaSignalStrength ss = - (android.hardware.radio.V1_2.WcdmaSignalStrength) wcdma; - ret = new CellSignalStrengthWcdma( - CellSignalStrength.getRssiDbmFromAsu(ss.base.signalStrength), - ss.base.bitErrorRate, CellSignalStrength.getRscpDbmFromAsu(ss.rscp), - CellSignalStrength.getEcNoDbFromAsu(ss.ecno)); - } - if (ret != null && ret.getRssi() == CellInfo.UNAVAILABLE - && ret.getRscp() == CellInfo.UNAVAILABLE) { + android.hardware.radio.V1_2.WcdmaSignalStrength ss = + (android.hardware.radio.V1_2.WcdmaSignalStrength) wcdma; + CellSignalStrengthWcdma ret = new CellSignalStrengthWcdma( + CellSignalStrength.getRssiDbmFromAsu(ss.base.signalStrength), + ss.base.bitErrorRate, CellSignalStrength.getRscpDbmFromAsu(ss.rscp), + CellSignalStrength.getEcNoDbFromAsu(ss.ecno)); + if (ret.getRssi() == CellInfo.UNAVAILABLE && ret.getRscp() == CellInfo.UNAVAILABLE) { ret.setDefaultValues(); ret.updateLevel(null, null); } @@ -3228,29 +3017,18 @@ public class RILUtils { } /** - * Convert a TdScdmaSignalStrength defined in radio/1.0/types.hal or TdscdmaSignalStrength - * defined in radio/1.2/types.hal to CellSignalStrengthTdscdma - * @param tdscdma TdScdmaSignalStrength defined in radio/1.0/types.hal or TdscdmaSignalStrength - * defined in radio/1.2/types.hal + * Convert a TdscdmaSignalStrength defined in radio/1.2/types.hal to CellSignalStrengthTdscdma + * @param tdscdma TdscdmaSignalStrength defined in radio/1.2/types.hal * @return The converted CellSignalStrengthTdscdma */ public static CellSignalStrengthTdscdma convertHalTdscdmaSignalStrength(Object tdscdma) { if (tdscdma == null) return null; - CellSignalStrengthTdscdma ret = null; - if (tdscdma instanceof android.hardware.radio.V1_0.TdScdmaSignalStrength) { - android.hardware.radio.V1_0.TdScdmaSignalStrength ss = - (android.hardware.radio.V1_0.TdScdmaSignalStrength) tdscdma; - ret = new CellSignalStrengthTdscdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, - ss.rscp != CellInfo.UNAVAILABLE ? -ss.rscp : ss.rscp); - } else if (tdscdma instanceof android.hardware.radio.V1_2.TdscdmaSignalStrength) { - android.hardware.radio.V1_2.TdscdmaSignalStrength ss = - (android.hardware.radio.V1_2.TdscdmaSignalStrength) tdscdma; - ret = new CellSignalStrengthTdscdma( - CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate, - CellSignalStrength.getRscpDbmFromAsu(ss.rscp)); - } - if (ret != null && ret.getRssi() == CellInfo.UNAVAILABLE - && ret.getRscp() == CellInfo.UNAVAILABLE) { + android.hardware.radio.V1_2.TdscdmaSignalStrength ss = + (android.hardware.radio.V1_2.TdscdmaSignalStrength) tdscdma; + CellSignalStrengthTdscdma ret = new CellSignalStrengthTdscdma( + CellSignalStrength.getRssiDbmFromAsu(ss.signalStrength), ss.bitErrorRate, + CellSignalStrength.getRscpDbmFromAsu(ss.rscp)); + if (ret.getRssi() == CellInfo.UNAVAILABLE && ret.getRscp() == CellInfo.UNAVAILABLE) { ret.setDefaultValues(); ret.updateLevel(null, null); } @@ -3435,9 +3213,9 @@ public class RILUtils { } /** - * Convert SetupDataCallResult defined in radio/1.0, 1.4, 1.5, 1.6/types.hal into + * Convert SetupDataCallResult defined in radio/1.4, 1.5, 1.6/types.hal into * DataCallResponse - * @param dcResult SetupDataCallResult defined in radio/1.0, 1.4, 1.5, 1.6/types.hal + * @param dcResult SetupDataCallResult defined in radio/1.4, 1.5, 1.6/types.hal * @return The converted DataCallResponse */ @VisibleForTesting @@ -3448,10 +3226,10 @@ public class RILUtils { long suggestedRetryTime; String ifname; int protocolType; - String[] addresses = null; - String[] dnses = null; - String[] gateways = null; - String[] pcscfs = null; + String[] addresses; + String[] dnses; + String[] gateways; + String[] pcscfs; Qos defaultQos = null; @DataCallResponse.HandoverFailureMode int handoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY; @@ -3461,34 +3239,7 @@ public class RILUtils { NetworkSliceInfo sliceInfo = null; List<TrafficDescriptor> trafficDescriptors = new ArrayList<>(); - if (dcResult instanceof android.hardware.radio.V1_0.SetupDataCallResult) { - final android.hardware.radio.V1_0.SetupDataCallResult result = - (android.hardware.radio.V1_0.SetupDataCallResult) dcResult; - cause = result.status; - suggestedRetryTime = result.suggestedRetryTime; - cid = result.cid; - active = result.active; - protocolType = ApnSetting.getProtocolIntFromString(result.type); - ifname = result.ifname; - if (!TextUtils.isEmpty(result.addresses)) { - addresses = result.addresses.split("\\s+"); - } - if (!TextUtils.isEmpty(result.dnses)) { - dnses = result.dnses.split("\\s+"); - } - if (!TextUtils.isEmpty(result.gateways)) { - gateways = result.gateways.split("\\s+"); - } - if (!TextUtils.isEmpty(result.pcscf)) { - pcscfs = result.pcscf.split("\\s+"); - } - mtu = mtuV4 = mtuV6 = result.mtu; - if (addresses != null) { - for (String address : addresses) { - laList.add(convertToLinkAddress(address)); - } - } - } else if (dcResult instanceof android.hardware.radio.V1_4.SetupDataCallResult) { + if (dcResult instanceof android.hardware.radio.V1_4.SetupDataCallResult) { final android.hardware.radio.V1_4.SetupDataCallResult result = (android.hardware.radio.V1_4.SetupDataCallResult) dcResult; cause = result.cause; @@ -3517,7 +3268,7 @@ public class RILUtils { protocolType = result.type; ifname = result.ifname; laList = result.addresses.stream().map(la -> convertToLinkAddress( - la.address, la.properties, la.deprecationTime, la.expirationTime)) + la.address, la.properties, la.deprecationTime, la.expirationTime)) .collect(Collectors.toList()); dnses = result.dnses.toArray(new String[0]); gateways = result.gateways.toArray(new String[0]); @@ -3535,7 +3286,7 @@ public class RILUtils { protocolType = result.type; ifname = result.ifname; laList = result.addresses.stream().map(la -> convertToLinkAddress( - la.address, la.properties, la.deprecationTime, la.expirationTime)) + la.address, la.properties, la.deprecationTime, la.expirationTime)) .collect(Collectors.toList()); dnses = result.dnses.toArray(new String[0]); gateways = result.gateways.toArray(new String[0]); @@ -3803,23 +3554,24 @@ public class RILUtils { public static NetworkSlicingConfig convertHalSlicingConfig( android.hardware.radio.V1_6.SlicingConfig sc) { List<UrspRule> urspRules = sc.urspRules.stream().map(ur -> new UrspRule(ur.precedence, - ur.trafficDescriptors.stream() - .map(td -> { - try { - return convertHalTrafficDescriptor(td); - } catch (IllegalArgumentException e) { - loge("convertHalSlicingConfig: Failed to convert traffic descriptor" - + ". e=" + e); - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()), - ur.routeSelectionDescriptor.stream().map(rsd -> new RouteSelectionDescriptor( - rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(), - rsd.sliceInfo.stream().map(RILUtils::convertHalSliceInfo) + ur.trafficDescriptors.stream() + .map(td -> { + try { + return convertHalTrafficDescriptor(td); + } catch (IllegalArgumentException e) { + loge("convertHalSlicingConfig: Failed to convert traffic " + + "descriptor. e=" + e); + return null; + } + }) + .filter(Objects::nonNull) .collect(Collectors.toList()), - rsd.dnn)).collect(Collectors.toList()))) + ur.routeSelectionDescriptor.stream().map( + rsd -> new RouteSelectionDescriptor(rsd.precedence, + rsd.sessionType.value(), rsd.sscMode.value(), + rsd.sliceInfo.stream().map(RILUtils::convertHalSliceInfo) + .collect(Collectors.toList()), + rsd.dnn)).collect(Collectors.toList()))) .collect(Collectors.toList()); return new NetworkSlicingConfig(urspRules, sc.sliceInfo.stream() .map(RILUtils::convertHalSliceInfo).collect(Collectors.toList())); @@ -4040,10 +3792,10 @@ public class RILUtils { } /** - * Convert a list of SetupDataCallResult defined in radio/1.0, 1.4, 1.5, 1.6/types.hal into + * Convert a list of SetupDataCallResult defined in radio/1.4, 1.5, 1.6/types.hal into * a list of DataCallResponse * @param dataCallResultList List of SetupDataCallResult defined in - * radio/1.0, 1.4, 1.5, 1.6/types.hal + * radio/1.4, 1.5, 1.6/types.hal * @return The converted list of DataCallResponses */ @VisibleForTesting @@ -4133,8 +3885,8 @@ public class RILUtils { } /** - * Convert Call defined in radio/1.0, 1.2, 1.6/types.hal to DriverCall - * @param halCall Call defined in radio/1.0, 1.2, 1.6/types.hal + * Convert Call defined in radio/1.2, 1.6/types.hal to DriverCall + * @param halCall Call defined in radio/1.2, 1.6/types.hal * @return The converted DriverCall */ public static DriverCall convertToDriverCall(Object halCall) { @@ -4150,17 +3902,13 @@ public class RILUtils { call16 = null; call12 = (android.hardware.radio.V1_2.Call) halCall; call10 = call12.base; - } else if (halCall instanceof android.hardware.radio.V1_0.Call) { - call16 = null; - call12 = null; - call10 = (android.hardware.radio.V1_0.Call) halCall; } else { call16 = null; call12 = null; call10 = null; } if (call10 != null) { - dc.state = DriverCall.stateFromCLCC((int) (call10.state)); + dc.state = DriverCall.stateFromCLCC(call10.state); dc.index = call10.index; dc.TOA = call10.toa; dc.isMpty = call10.isMpty; @@ -4169,10 +3917,9 @@ public class RILUtils { dc.isVoice = call10.isVoice; dc.isVoicePrivacy = call10.isVoicePrivacy; dc.number = call10.number; - dc.numberPresentation = DriverCall.presentationFromCLIP( - (int) (call10.numberPresentation)); + dc.numberPresentation = DriverCall.presentationFromCLIP(call10.numberPresentation); dc.name = call10.name; - dc.namePresentation = DriverCall.presentationFromCLIP((int) (call10.namePresentation)); + dc.namePresentation = DriverCall.presentationFromCLIP(call10.namePresentation); if (call10.uusInfo.size() == 1) { dc.uusInfo = new UUSInfo(); dc.uusInfo.setType(call10.uusInfo.get(0).uusType); @@ -4186,7 +3933,7 @@ public class RILUtils { dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA); } if (call12 != null) { - dc.audioQuality = (int) (call12.audioQuality); + dc.audioQuality = call12.audioQuality; } if (call16 != null) { dc.forwardedNumber = call16.forwardedNumber; @@ -4201,7 +3948,7 @@ public class RILUtils { */ public static DriverCall convertToDriverCall(android.hardware.radio.voice.Call halCall) { DriverCall dc = new DriverCall(); - dc.state = DriverCall.stateFromCLCC((int) halCall.state); + dc.state = DriverCall.stateFromCLCC(halCall.state); dc.index = halCall.index; dc.TOA = halCall.toa; dc.isMpty = halCall.isMpty; @@ -4210,9 +3957,9 @@ public class RILUtils { dc.isVoice = halCall.isVoice; dc.isVoicePrivacy = halCall.isVoicePrivacy; dc.number = halCall.number; - dc.numberPresentation = DriverCall.presentationFromCLIP((int) halCall.numberPresentation); + dc.numberPresentation = DriverCall.presentationFromCLIP(halCall.numberPresentation); dc.name = halCall.name; - dc.namePresentation = DriverCall.presentationFromCLIP((int) halCall.namePresentation); + dc.namePresentation = DriverCall.presentationFromCLIP(halCall.namePresentation); if (halCall.uusInfo.length == 1) { dc.uusInfo = new UUSInfo(); dc.uusInfo.setType(halCall.uusInfo[0].uusType); @@ -4223,7 +3970,7 @@ public class RILUtils { } // Make sure there's a leading + on addresses with a TOA of 145 dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA); - dc.audioQuality = (int) halCall.audioQuality; + dc.audioQuality = halCall.audioQuality; dc.forwardedNumber = halCall.forwardedNumber; return dc; } @@ -5377,6 +5124,10 @@ public class RILUtils { return "SET_N1_MODE_ENABLED"; case RIL_REQUEST_IS_N1_MODE_ENABLED: return "IS_N1_MODE_ENABLED"; + case RIL_REQUEST_SET_LOCATION_PRIVACY_SETTING: + return "SET_LOCATION_PRIVACY_SETTING"; + case RIL_REQUEST_GET_LOCATION_PRIVACY_SETTING: + return "GET_LOCATION_PRIVACY_SETTING"; default: return "<unknown request " + request + ">"; } @@ -5514,12 +5265,14 @@ public class RILUtils { return "UNSOL_BARRING_INFO_CHANGED"; case RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT: return "UNSOL_EMERGENCY_NETWORK_SCAN_RESULT"; - case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: - return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; case RIL_UNSOL_CONNECTION_SETUP_FAILURE: return "UNSOL_CONNECTION_SETUP_FAILURE"; case RIL_UNSOL_NOTIFY_ANBR: return "UNSOL_NOTIFY_ANBR"; + case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: + return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; + case RIL_UNSOL_IMEI_MAPPING_CHANGED: + return "UNSOL_IMEI_MAPPING_CHANGED"; default: return "<unknown response " + response + ">"; } @@ -5636,7 +5389,7 @@ public class RILUtils { try { val = o.getClass().getDeclaredMethod(getTagMethod).invoke(o); } catch (NoSuchMethodException | IllegalAccessException - | InvocationTargetException e) { + | InvocationTargetException e) { loge(e.toString()); } if (val != null) { @@ -5905,47 +5658,6 @@ public class RILUtils { } /** - * Convert satellite-related errors from CommandException.Error to - * SatelliteManager.SatelliteServiceResult. - * @param error The satellite error. - * @return The converted SatelliteServiceResult. - */ - @SatelliteManager.SatelliteError - public static int convertToSatelliteError( - CommandException.Error error) { - switch (error) { - case INTERNAL_ERR: - //fallthrough to SYSTEM_ERR - case MODEM_ERR: - //fallthrough to SYSTEM_ERR - case SYSTEM_ERR: - return SatelliteManager.SATELLITE_MODEM_ERROR; - case INVALID_ARGUMENTS: - return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; - case INVALID_MODEM_STATE: - return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; - case RADIO_NOT_AVAILABLE: - return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; - case REQUEST_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; - case NO_MEMORY: - //fallthrough to NO_RESOURCES - case NO_RESOURCES: - return SatelliteManager.SATELLITE_NO_RESOURCES; - case NETWORK_ERR: - return SatelliteManager.SATELLITE_NETWORK_ERROR; - case NO_NETWORK_FOUND: - return SatelliteManager.SATELLITE_NOT_REACHABLE; - case ABORTED: - return SatelliteManager.SATELLITE_REQUEST_ABORTED; - case ACCESS_BARRED: - return SatelliteManager.SATELLITE_ACCESS_BARRED; - default: - return SatelliteManager.SATELLITE_ERROR; - } - } - - /** * Converts the call state to HAL IMS call state. * * @param state The {@link Call.State}. @@ -5964,6 +5676,20 @@ public class RILUtils { } } + /** Convert an AIDL-based CellularIdentifierDisclosure to its Java wrapper. */ + public static CellularIdentifierDisclosure convertCellularIdentifierDisclosure( + android.hardware.radio.network.CellularIdentifierDisclosure identifierDisclsoure) { + if (identifierDisclsoure == null) { + return null; + } + + return new CellularIdentifierDisclosure( + identifierDisclsoure.protocolMessage, + identifierDisclsoure.identifier, + identifierDisclsoure.plmn, + identifierDisclsoure.isEmergency); + } + private static void logd(String log) { Rlog.d("RILUtils", log); } diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java index 3e2be1d6ae..6bf0203cb8 100644 --- a/src/java/com/android/internal/telephony/RadioConfig.java +++ b/src/java/com/android/internal/telephony/RadioConfig.java @@ -61,7 +61,6 @@ public class RadioConfig extends Handler { static final int EVENT_HIDL_SERVICE_DEAD = 1; static final int EVENT_AIDL_SERVICE_DEAD = 2; static final HalVersion RADIO_CONFIG_HAL_VERSION_UNKNOWN = new HalVersion(-1, -1); - static final HalVersion RADIO_CONFIG_HAL_VERSION_1_0 = new HalVersion(1, 0); static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1); static final HalVersion RADIO_CONFIG_HAL_VERSION_1_3 = new HalVersion(1, 3); static final HalVersion RADIO_CONFIG_HAL_VERSION_2_0 = new HalVersion(2, 0); @@ -317,13 +316,7 @@ public class RadioConfig extends Handler { } if (mRadioConfigProxy.isEmpty()) { - try { - mRadioConfigProxy.setHidl(RADIO_CONFIG_HAL_VERSION_1_0, - android.hardware.radio.config.V1_0.IRadioConfig.getService(true)); - } catch (RemoteException | NoSuchElementException e) { - mRadioConfigProxy.clear(); - loge("getHidlRadioConfigProxy1_0: RadioConfigProxy getService | linkToDeath: " + e); - } + loge("IRadioConfig <1.1 is no longer supported."); } if (!mRadioConfigProxy.isEmpty()) { diff --git a/src/java/com/android/internal/telephony/RadioConfigProxy.java b/src/java/com/android/internal/telephony/RadioConfigProxy.java index edeb558b5d..9d05fc5fc3 100644 --- a/src/java/com/android/internal/telephony/RadioConfigProxy.java +++ b/src/java/com/android/internal/telephony/RadioConfigProxy.java @@ -35,7 +35,7 @@ public class RadioConfigProxy { private final RadioConfigHidlServiceDeathRecipient mRadioConfigHidlServiceDeathRecipient; private final RadioConfigAidlServiceDeathRecipient mRadioConfigAidlServiceDeathRecipient; - private volatile android.hardware.radio.config.V1_0.IRadioConfig mHidlRadioConfigProxy = null; + private volatile android.hardware.radio.config.V1_1.IRadioConfig mHidlRadioConfigProxy = null; private volatile android.hardware.radio.config.IRadioConfig mAidlRadioConfigProxy = null; private HalVersion mRadioConfigHalVersion = RadioConfig.RADIO_CONFIG_HAL_VERSION_UNKNOWN; @@ -57,7 +57,7 @@ public class RadioConfigProxy { */ public void setHidl( HalVersion radioConfigHalVersion, - android.hardware.radio.config.V1_0.IRadioConfig radioConfig) { + android.hardware.radio.config.V1_1.IRadioConfig radioConfig) { mRadioConfigHalVersion = radioConfigHalVersion; mHidlRadioConfigProxy = radioConfig; mIsAidl = false; @@ -65,19 +65,11 @@ public class RadioConfigProxy { } /** - * Get HIDL IRadioConfig V1_0 - * @return IRadioConfigV1_0 - */ - public android.hardware.radio.config.V1_0.IRadioConfig getHidl10() { - return mHidlRadioConfigProxy; - } - - /** * Get HIDL IRadioConfig V1_1 * @return IRadioConfigV1_1 */ public android.hardware.radio.config.V1_1.IRadioConfig getHidl11() { - return (android.hardware.radio.config.V1_1.IRadioConfig) mHidlRadioConfigProxy; + return mHidlRadioConfigProxy; } /** @@ -192,7 +184,7 @@ public class RadioConfigProxy { if (isAidl()) { getAidl().getSimSlotsStatus(serial); } else { - getHidl10().getSimSlotsStatus(serial); + getHidl11().getSimSlotsStatus(serial); } } @@ -227,7 +219,7 @@ public class RadioConfigProxy { if (isAidl()) { getAidl().setSimSlotsMapping(serial, RILUtils.convertSimSlotsMapping(slotMapping)); } else { - getHidl10().setSimSlotsMapping(serial, + getHidl11().setSimSlotsMapping(serial, RILUtils.convertSlotMappingToList(slotMapping)); } } @@ -265,13 +257,13 @@ public class RadioConfigProxy { private static final String TAG = "RadioConfigHidlSDR"; private final RadioConfig mRadioConfig; - private android.hardware.radio.config.V1_0.IRadioConfig mService; + private android.hardware.radio.config.V1_1.IRadioConfig mService; RadioConfigHidlServiceDeathRecipient(RadioConfig radioConfig) { mRadioConfig = radioConfig; } - public void setService(android.hardware.radio.config.V1_0.IRadioConfig service) { + public void setService(android.hardware.radio.config.V1_1.IRadioConfig service) { mService = service; } diff --git a/src/java/com/android/internal/telephony/RadioDataProxy.java b/src/java/com/android/internal/telephony/RadioDataProxy.java index 9671077b0f..40db9e5b3d 100644 --- a/src/java/com/android/internal/telephony/RadioDataProxy.java +++ b/src/java/com/android/internal/telephony/RadioDataProxy.java @@ -22,9 +22,7 @@ import android.os.AsyncResult; import android.os.Message; import android.os.RemoteException; import android.telephony.Rlog; -import android.telephony.ServiceState; import android.telephony.data.DataProfile; -import android.telephony.data.DataService; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; @@ -34,8 +32,8 @@ import java.net.InetAddress; import java.util.ArrayList; /** - * A holder for IRadioData. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioData and call the AIDL implementations of the HAL APIs. + * A holder for IRadioData. + * Use getAidl to get IRadioData and call the AIDL implementations of the HAL APIs. */ public class RadioDataProxy extends RadioServiceProxy { private static final String TAG = "RadioDataProxy"; @@ -129,12 +127,8 @@ public class RadioDataProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { mDataProxy.deactivateDataCall(serial, cid, reason); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2)) { - ((android.hardware.radio.V1_2.IRadio) mRadioProxy).deactivateDataCall_1_2( - serial, cid, reason); } else { - mRadioProxy.deactivateDataCall(serial, cid, - reason == DataService.REQUEST_REASON_SHUTDOWN); + mRadioProxy.deactivateDataCall_1_2(serial, cid, reason); } } @@ -216,11 +210,9 @@ public class RadioDataProxy extends RadioServiceProxy { * Call IRadioData#setDataProfile * @param serial Serial number of request * @param profiles Array of DataProfiles to set - * @param isRoaming Whether or not the device is roaming * @throws RemoteException */ - public void setDataProfile(int serial, DataProfile[] profiles, boolean isRoaming) - throws RemoteException { + public void setDataProfile(int serial, DataProfile[] profiles) throws RemoteException { if (isEmpty()) return; if (isAidl()) { android.hardware.radio.data.DataProfileInfo[] dpis = @@ -235,22 +227,12 @@ public class RadioDataProxy extends RadioServiceProxy { dpis.add(RILUtils.convertToHalDataProfile15(dp)); } ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setDataProfile_1_5(serial, dpis); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { + } else { ArrayList<android.hardware.radio.V1_4.DataProfileInfo> dpis = new ArrayList<>(); for (DataProfile dp : profiles) { dpis.add(RILUtils.convertToHalDataProfile14(dp)); } - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).setDataProfile_1_4(serial, dpis); - } else { - ArrayList<android.hardware.radio.V1_0.DataProfileInfo> dpis = new ArrayList<>(); - for (DataProfile dp : profiles) { - if (dp.isPersistent()) { - dpis.add(RILUtils.convertToHalDataProfile10(dp)); - } - } - if (!dpis.isEmpty()) { - mRadioProxy.setDataProfile(serial, dpis, isRoaming); - } + mRadioProxy.setDataProfile_1_4(serial, dpis); } } @@ -277,10 +259,9 @@ public class RadioDataProxy extends RadioServiceProxy { * Call IRadioData#setInitialAttachApn * @param serial Serial number of request * @param dataProfile Data profile containing APN settings - * @param isRoaming Whether or not the device is roaming * @throws RemoteException */ - public void setInitialAttachApn(int serial, DataProfile dataProfile, boolean isRoaming) + public void setInitialAttachApn(int serial, DataProfile dataProfile) throws RemoteException { if (isEmpty()) return; if (isAidl()) { @@ -288,22 +269,17 @@ public class RadioDataProxy extends RadioServiceProxy { } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setInitialAttachApn_1_5(serial, RILUtils.convertToHalDataProfile15(dataProfile)); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).setInitialAttachApn_1_4(serial, - RILUtils.convertToHalDataProfile14(dataProfile)); } else { - mRadioProxy.setInitialAttachApn(serial, RILUtils.convertToHalDataProfile10(dataProfile), - dataProfile.isPersistent(), isRoaming); + mRadioProxy.setInitialAttachApn_1_4(serial, + RILUtils.convertToHalDataProfile14(dataProfile)); } } /** * Call IRadioData#setupDataCall * @param serial Serial number of request - * @param phoneId Phone ID of the requestor * @param accessNetwork Access network to setup the data call * @param dataProfileInfo Data profile info - * @param isRoaming Whether or not the device is roaming * @param roamingAllowed Whether or not data roaming is allowed by the user * @param reason Request reason * @param linkProperties LinkProperties containing address and DNS info @@ -316,15 +292,14 @@ public class RadioDataProxy extends RadioServiceProxy { * is allowed * @throws RemoteException */ - public void setupDataCall(int serial, int phoneId, int accessNetwork, - DataProfile dataProfileInfo, boolean isRoaming, boolean roamingAllowed, int reason, - LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, - TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed) - throws RemoteException { + public void setupDataCall(int serial, int accessNetwork, DataProfile dataProfileInfo, + boolean roamingAllowed, int reason, LinkProperties linkProperties, int pduSessionId, + NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, + boolean matchAllRuleAllowed) throws RemoteException { if (isEmpty()) return; ArrayList<String> addresses = new ArrayList<>(); ArrayList<String> dnses = new ArrayList<>(); - String[] dnsesArr = null; + String[] dnsesArr; if (linkProperties != null) { for (InetAddress address : linkProperties.getAddresses()) { addresses.add(address.getHostAddress()); @@ -361,31 +336,10 @@ public class RadioDataProxy extends RadioServiceProxy { accessNetwork, RILUtils.convertToHalDataProfile15(dataProfileInfo), roamingAllowed, reason, RILUtils.convertToHalLinkProperties15(linkProperties), dnses); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).setupDataCall_1_4(serial, - accessNetwork, RILUtils.convertToHalDataProfile14(dataProfileInfo), - roamingAllowed, reason, addresses, dnses); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2)) { - ((android.hardware.radio.V1_2.IRadio) mRadioProxy).setupDataCall_1_2(serial, - accessNetwork, RILUtils.convertToHalDataProfile10(dataProfileInfo), - dataProfileInfo.isPersistent(), roamingAllowed, isRoaming, reason, addresses, - dnses); } else { - // Getting data RAT here is just a workaround to support the older 1.0 vendor RIL. - // The new data service interface passes access network type instead of RAT for - // setup data request. It is impossible to convert access network type back to RAT here, - // so we directly get the data RAT from phone. - int dataRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - Phone phone = PhoneFactory.getPhone(phoneId); - if (phone != null) { - ServiceState ss = phone.getServiceState(); - if (ss != null) { - dataRat = ss.getRilDataRadioTechnology(); - } - } - mRadioProxy.setupDataCall(serial, dataRat, - RILUtils.convertToHalDataProfile10(dataProfileInfo), - dataProfileInfo.isPersistent(), roamingAllowed, isRoaming); + mRadioProxy.setupDataCall_1_4(serial, accessNetwork, + RILUtils.convertToHalDataProfile14(dataProfileInfo), + roamingAllowed, reason, addresses, dnses); } } @@ -415,7 +369,7 @@ public class RadioDataProxy extends RadioServiceProxy { */ public void startKeepalive(int serial, int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_1)) return; + if (isEmpty()) return; if (isAidl()) { android.hardware.radio.data.KeepaliveRequest req = new android.hardware.radio.data.KeepaliveRequest(); @@ -476,7 +430,7 @@ public class RadioDataProxy extends RadioServiceProxy { req.destinationPort = packetData.getDstPort(); req.maxKeepaliveIntervalMillis = intervalMillis; - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).startKeepalive(serial, req); + mRadioProxy.startKeepalive(serial, req); } } @@ -487,11 +441,11 @@ public class RadioDataProxy extends RadioServiceProxy { * @throws RemoteException */ public void stopKeepalive(int serial, int sessionHandle) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_1)) return; + if (isEmpty()) return; if (isAidl()) { mDataProxy.stopKeepalive(serial, sessionHandle); } else { - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).stopKeepalive(serial, sessionHandle); + mRadioProxy.stopKeepalive(serial, sessionHandle); } } } diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java index 4f75412ad9..aadfe62499 100644 --- a/src/java/com/android/internal/telephony/RadioIndication.java +++ b/src/java/com/android/internal/telephony/RadioIndication.java @@ -240,28 +240,18 @@ public class RadioIndication extends IRadioIndication.Stub { } public void currentSignalStrength(int indicationType, - android.hardware.radio.V1_0.SignalStrength signalStrength) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - - SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength); - - SignalStrength ss = mRil.fixupSignalStrength10(ssInitial); - // Note this is set to "verbose" because it happens frequently - if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); - - if (mRil.mSignalStrengthRegistrant != null) { - mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult (null, ss, null)); - } + android.hardware.radio.V1_0.SignalStrength signalStrength) { + mRil.unsljLogMore(RIL_UNSOL_SIGNAL_STRENGTH, "unsupported on IRadio < 1.4"); } /** * Indicates current link capacity estimate. */ public void currentLinkCapacityEstimate(int indicationType, - android.hardware.radio.V1_2.LinkCapacityEstimate lce) { + android.hardware.radio.V1_2.LinkCapacityEstimate lce) { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - List<LinkCapacityEstimate> response = RILUtils.convertHalLceData(lce); + List<LinkCapacityEstimate> response = RILUtils.convertHalLinkCapacityEstimate(lce); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); @@ -277,7 +267,7 @@ public class RadioIndication extends IRadioIndication.Stub { android.hardware.radio.V1_6.LinkCapacityEstimate lce) { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - List<LinkCapacityEstimate> response = RILUtils.convertHalLceData(lce); + List<LinkCapacityEstimate> response = RILUtils.convertHalLinkCapacityEstimate(lce); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); @@ -290,16 +280,8 @@ public class RadioIndication extends IRadioIndication.Stub { * Indicates the current signal strength of the camped or primary serving cell. */ public void currentSignalStrength_1_2(int indicationType, - android.hardware.radio.V1_2.SignalStrength signalStrength) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - - SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); - // Note this is set to "verbose" because it happens frequently - if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); - - if (mRil.mSignalStrengthRegistrant != null) { - mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null)); - } + android.hardware.radio.V1_2.SignalStrength signalStrength) { + mRil.unsljLogMore(RIL_UNSOL_SIGNAL_STRENGTH, "unsupported on IRadio < 1.4"); } /** @@ -359,8 +341,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentPhysicalChannelConfigs(int indicationType, ArrayList<android.hardware.radio.V1_2.PhysicalChannelConfig> configs) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - physicalChannelConfigsIndication(configs); + mRil.unsljLogMore(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, "unsupported on IRadio < 1.4"); } /** @@ -393,7 +374,7 @@ public class RadioIndication extends IRadioIndication.Stub { /** Indicates current data call list. */ public void dataCallListChanged(int indicationType, ArrayList<android.hardware.radio.V1_0.SetupDataCallResult> dcList) { - responseDataCallListChanged(indicationType, dcList); + mRil.unsljLogMore(RIL_UNSOL_DATA_CALL_LIST_CHANGED, "unsupported on IRadio < 1.4"); } /** Indicates current data call list with radio HAL 1.4. */ @@ -803,15 +784,13 @@ public class RadioIndication extends IRadioIndication.Stub { /** Get unsolicited message for cellInfoList */ public void cellInfoList(int indicationType, ArrayList<android.hardware.radio.V1_0.CellInfo> records) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - responseCellInfoList(records); + mRil.unsljLogMore(RIL_UNSOL_CELL_INFO_LIST, "unsupported on IRadio < 1.4"); } /** Get unsolicited message for cellInfoList using HAL V1_2 */ public void cellInfoList_1_2(int indicationType, ArrayList<android.hardware.radio.V1_2.CellInfo> records) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - responseCellInfoList(records); + mRil.unsljLogMore(RIL_UNSOL_CELL_INFO_LIST, "unsupported on IRadio < 1.4"); } /** Get unsolicited message for cellInfoList using HAL V1_4 */ @@ -854,20 +833,20 @@ public class RadioIndication extends IRadioIndication.Stub { /** Incremental network scan results */ public void networkScanResult(int indicationType, - android.hardware.radio.V1_1.NetworkScanResult result) { - responseNetworkScan(indicationType, result); + android.hardware.radio.V1_1.NetworkScanResult result) { + mRil.unsljLogMore(RIL_UNSOL_NETWORK_SCAN_RESULT, "unsupported on IRadio < 1.4"); } /** Incremental network scan results with HAL V1_2 */ public void networkScanResult_1_2(int indicationType, - android.hardware.radio.V1_2.NetworkScanResult result) { - responseNetworkScan_1_2(indicationType, result); + android.hardware.radio.V1_2.NetworkScanResult result) { + mRil.unsljLogMore(RIL_UNSOL_NETWORK_SCAN_RESULT, "unsupported on IRadio < 1.4"); } /** Incremental network scan results with HAL V1_4 */ public void networkScanResult_1_4(int indicationType, - android.hardware.radio.V1_4.NetworkScanResult result) { - responseNetworkScan_1_4(indicationType, result); + android.hardware.radio.V1_4.NetworkScanResult result) { + responseNetworkScan(indicationType, result); } /** Incremental network scan results with HAL V1_5 */ @@ -918,8 +897,7 @@ public class RadioIndication extends IRadioIndication.Stub { new AsyncResult (null, response, null)); } - public void hardwareConfigChanged( - int indicationType, + public void hardwareConfigChanged(int indicationType, ArrayList<android.hardware.radio.V1_0.HardwareConfig> configs) { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); @@ -932,7 +910,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void radioCapabilityIndication(int indicationType, - android.hardware.radio.V1_0.RadioCapability rc) { + android.hardware.radio.V1_0.RadioCapability rc) { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); RadioCapability response = RILUtils.convertHalRadioCapability(rc, mRil); @@ -1002,15 +980,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void lceData(int indicationType, LceDataInfo lce) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - - List<LinkCapacityEstimate> response = RILUtils.convertHalLceData(lce); - - if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); - - if (mRil.mLceInfoRegistrants != null) { - mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); - } + mRil.unsljLogMore(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, "unsupported on IRadio < 1.4"); } public void pcoData(int indicationType, PcoDataInfo pco) { @@ -1198,16 +1168,7 @@ public class RadioIndication extends IRadioIndication.Stub { List<PhysicalChannelConfig> response = new ArrayList<>(configs.size()); try { for (Object obj : configs) { - if (obj instanceof android.hardware.radio.V1_2.PhysicalChannelConfig) { - android.hardware.radio.V1_2.PhysicalChannelConfig config = - (android.hardware.radio.V1_2.PhysicalChannelConfig) obj; - - response.add(new PhysicalChannelConfig.Builder() - .setCellConnectionStatus(RILUtils.convertHalCellConnectionStatus( - config.status)) - .setCellBandwidthDownlinkKhz(config.cellBandwidthDownlink) - .build()); - } else if (obj instanceof android.hardware.radio.V1_4.PhysicalChannelConfig) { + if (obj instanceof android.hardware.radio.V1_4.PhysicalChannelConfig) { android.hardware.radio.V1_4.PhysicalChannelConfig config = (android.hardware.radio.V1_4.PhysicalChannelConfig) obj; PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder(); @@ -1243,7 +1204,11 @@ public class RadioIndication extends IRadioIndication.Stub { } if (band == PhysicalChannelConfig.BAND_UNKNOWN) { mRil.riljLoge("Unsupported unknown band."); - return; + // TODO, b/288310456, + // If the band is unknown, PhysicalChannelConfig can be built without + // setBand. It should be enforced not to allow "unknown" bands in the + // near future. + // return; } else { builder.setBand(band); } @@ -1277,28 +1242,6 @@ public class RadioIndication extends IRadioIndication.Stub { } private void responseNetworkScan(int indicationType, - android.hardware.radio.V1_1.NetworkScanResult result) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - - ArrayList<CellInfo> cellInfos = - RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); - NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); - mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); - } - - private void responseNetworkScan_1_2(int indicationType, - android.hardware.radio.V1_2.NetworkScanResult result) { - mRil.processIndication(HAL_SERVICE_RADIO, indicationType); - - ArrayList<CellInfo> cellInfos = - RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); - NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); - mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); - } - - private void responseNetworkScan_1_4(int indicationType, android.hardware.radio.V1_4.NetworkScanResult result) { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); diff --git a/src/java/com/android/internal/telephony/RadioMessagingProxy.java b/src/java/com/android/internal/telephony/RadioMessagingProxy.java index 69ccf3612a..c652284a11 100644 --- a/src/java/com/android/internal/telephony/RadioMessagingProxy.java +++ b/src/java/com/android/internal/telephony/RadioMessagingProxy.java @@ -25,8 +25,8 @@ import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import java.util.ArrayList; /** - * A holder for IRadioMessaging. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioMessaging and call the AIDL implementations of the HAL APIs. + * A holder for IRadioMessaging. + * Use getAidl to get IRadioMessaging and call the AIDL implementations of the HAL APIs. */ public class RadioMessagingProxy extends RadioServiceProxy { private static final String TAG = "RadioMessagingProxy"; diff --git a/src/java/com/android/internal/telephony/RadioModemProxy.java b/src/java/com/android/internal/telephony/RadioModemProxy.java index 4178293d06..cdcbcc063e 100644 --- a/src/java/com/android/internal/telephony/RadioModemProxy.java +++ b/src/java/com/android/internal/telephony/RadioModemProxy.java @@ -20,8 +20,8 @@ import android.os.RemoteException; import android.telephony.Rlog; /** - * A holder for IRadioModem. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioModem and call the AIDL implementations of the HAL APIs. + * A holder for IRadioModem. + * Use getAidl to get IRadioModem and call the AIDL implementations of the HAL APIs. */ public class RadioModemProxy extends RadioServiceProxy { private static final String TAG = "RadioModemProxy"; @@ -83,11 +83,11 @@ public class RadioModemProxy extends RadioServiceProxy { * @throws RemoteException */ public void enableModem(int serial, boolean on) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_3)) return; + if (isEmpty()) return; if (isAidl()) { mModemProxy.enableModem(serial, on); } else { - ((android.hardware.radio.V1_3.IRadio) mRadioProxy).enableModem(serial, on); + mRadioProxy.enableModem(serial, on); } } @@ -166,11 +166,11 @@ public class RadioModemProxy extends RadioServiceProxy { * @throws RemoteException */ public void getModemStackStatus(int serial) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_3)) return; + if (isEmpty()) return; if (isAidl()) { mModemProxy.getModemStackStatus(serial); } else { - ((android.hardware.radio.V1_3.IRadio) mRadioProxy).getModemStackStatus(serial); + mRadioProxy.getModemStackStatus(serial); } } diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 246c2e0204..4acc71acee 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -33,19 +33,17 @@ import java.util.List; import java.util.stream.Collectors; /** - * A holder for IRadioNetwork. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioNetwork and call the AIDL implementations of the HAL APIs. + * A holder for IRadioNetwork. + * Use getAidl to get IRadioNetwork and call the AIDL implementations of the HAL APIs. */ public class RadioNetworkProxy extends RadioServiceProxy { private static final String TAG = "RadioNetworkProxy"; private volatile android.hardware.radio.network.IRadioNetwork mNetworkProxy = null; - private static final int INDICATION_FILTERS_ALL_V1_0 = + private static final int INDICATION_FILTERS_ALL_V1_2 = android.hardware.radio.V1_5.IndicationFilter.SIGNAL_STRENGTH | android.hardware.radio.V1_5.IndicationFilter.FULL_NETWORK_STATE - | android.hardware.radio.V1_5.IndicationFilter.DATA_CALL_DORMANCY_CHANGED; - private static final int INDICATION_FILTERS_ALL_V1_2 = - INDICATION_FILTERS_ALL_V1_0 + | android.hardware.radio.V1_5.IndicationFilter.DATA_CALL_DORMANCY_CHANGED | android.hardware.radio.V1_5.IndicationFilter.LINK_CAPACITY_ESTIMATE | android.hardware.radio.V1_5.IndicationFilter.PHYSICAL_CHANNEL_CONFIG; private static final int INDICATION_FILTERS_ALL_V1_5 = @@ -121,11 +119,8 @@ public class RadioNetworkProxy extends RadioServiceProxy { mNetworkProxy.getAllowedNetworkTypesBitmap(serial); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getAllowedNetworkTypesBitmap(serial); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy) - .getPreferredNetworkTypeBitmap(serial); } else { - mRadioProxy.getPreferredNetworkType(serial); + mRadioProxy.getPreferredNetworkTypeBitmap(serial); } } @@ -278,10 +273,8 @@ public class RadioNetworkProxy extends RadioServiceProxy { mNetworkProxy.getSignalStrength(serial); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getSignalStrength_1_6(serial); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).getSignalStrength_1_4(serial); } else { - mRadioProxy.getSignalStrength(serial); + mRadioProxy.getSignalStrength_1_4(serial); } } @@ -394,12 +387,8 @@ public class RadioNetworkProxy extends RadioServiceProxy { public void setPreferredNetworkTypeBitmap(int serial, int networkTypesBitmask) throws RemoteException { if (isEmpty() || mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) return; - if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).setPreferredNetworkTypeBitmap(serial, - RILUtils.convertToHalRadioAccessFamily(networkTypesBitmask)); - } else { - mRadioProxy.setPreferredNetworkType(serial, networkTypesBitmask); - } + mRadioProxy.setPreferredNetworkTypeBitmap(serial, + RILUtils.convertToHalRadioAccessFamily(networkTypesBitmask)); } /** @@ -478,11 +467,8 @@ public class RadioNetworkProxy extends RadioServiceProxy { } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setIndicationFilter_1_5(serial, filter & INDICATION_FILTERS_ALL_V1_5); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2)) { - ((android.hardware.radio.V1_2.IRadio) mRadioProxy).setIndicationFilter_1_2(serial, - filter & INDICATION_FILTERS_ALL_V1_2); } else { - mRadioProxy.setIndicationFilter(serial, filter & INDICATION_FILTERS_ALL_V1_0); + mRadioProxy.setIndicationFilter_1_2(serial, filter & INDICATION_FILTERS_ALL_V1_2); } } @@ -504,7 +490,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { public void setLinkCapacityReportingCriteria(int serial, int hysteresisMs, int hysteresisDlKbps, int hysteresisUlKbps, int[] thresholdsDlKbps, int[] thresholdsUlKbps, int ran) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_2)) return; + if (isEmpty()) return; if (isAidl()) { mNetworkProxy.setLinkCapacityReportingCriteria(serial, hysteresisMs, hysteresisDlKbps, hysteresisUlKbps, thresholdsDlKbps, thresholdsUlKbps, @@ -519,7 +505,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { if (ran == AccessNetworkConstants.AccessNetworkType.NGRAN) { throw new RuntimeException("NGRAN unsupported on IRadio version: " + mHalVersion); } - ((android.hardware.radio.V1_2.IRadio) mRadioProxy).setLinkCapacityReportingCriteria( + mRadioProxy.setLinkCapacityReportingCriteria( serial, hysteresisMs, hysteresisDlKbps, hysteresisUlKbps, RILUtils.primitiveArrayToArrayList(thresholdsDlKbps), RILUtils.primitiveArrayToArrayList(thresholdsUlKbps), @@ -603,7 +589,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { */ public void setSignalStrengthReportingCriteria(int serial, @NonNull List<SignalThresholdInfo> signalThresholdInfos) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_2)) return; + if (isEmpty()) return; if (isAidl()) { android.hardware.radio.network.SignalThresholdInfo[] halSignalThresholdsInfos = new android.hardware.radio.network.SignalThresholdInfo[signalThresholdInfos.size()]; @@ -622,14 +608,12 @@ public class RadioNetworkProxy extends RadioServiceProxy { } } else { for (SignalThresholdInfo signalThresholdInfo : signalThresholdInfos) { - ((android.hardware.radio.V1_2.IRadio) mRadioProxy) - .setSignalStrengthReportingCriteria(serial, - signalThresholdInfo.getHysteresisMs(), - signalThresholdInfo.getHysteresisDb(), - RILUtils.primitiveArrayToArrayList( - signalThresholdInfo.getThresholds()), - RILUtils.convertToHalAccessNetwork( - signalThresholdInfo.getRadioAccessNetworkType())); + mRadioProxy.setSignalStrengthReportingCriteria(serial, + signalThresholdInfo.getHysteresisMs(), + signalThresholdInfo.getHysteresisDb(), + RILUtils.primitiveArrayToArrayList(signalThresholdInfo.getThresholds()), + RILUtils.convertToHalAccessNetwork( + signalThresholdInfo.getRadioAccessNetworkType())); } } } @@ -657,7 +641,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { */ public void setSystemSelectionChannels(int serial, List<RadioAccessSpecifier> specifiers) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_3)) return; + if (isEmpty()) return; if (isAidl()) { mNetworkProxy.setSystemSelectionChannels(serial, !specifiers.isEmpty(), specifiers.stream().map(RILUtils::convertToHalRadioAccessSpecifierAidl) @@ -668,8 +652,8 @@ public class RadioNetworkProxy extends RadioServiceProxy { .map(RILUtils::convertToHalRadioAccessSpecifier15) .collect(Collectors.toCollection(ArrayList::new))); } else { - ((android.hardware.radio.V1_3.IRadio) mRadioProxy).setSystemSelectionChannels( - serial, !specifiers.isEmpty(), specifiers.stream() + mRadioProxy.setSystemSelectionChannels(serial, !specifiers.isEmpty(), + specifiers.stream() .map(RILUtils::convertToHalRadioAccessSpecifier11) .collect(Collectors.toCollection(ArrayList::new))); } @@ -684,7 +668,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { */ public void startNetworkScan(int serial, NetworkScanRequest request, HalVersion overrideHalVersion, Message result) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_1)) return; + if (isEmpty()) return; if (isAidl()) { android.hardware.radio.network.NetworkScanRequest halRequest = new android.hardware.radio.network.NetworkScanRequest(); @@ -734,7 +718,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { } ((android.hardware.radio.V1_5.IRadio) mRadioProxy).startNetworkScan_1_5( serial, halRequest); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2)) { + } else { android.hardware.radio.V1_2.NetworkScanRequest halRequest = new android.hardware.radio.V1_2.NetworkScanRequest(); halRequest.type = request.getScanType(); @@ -755,31 +739,7 @@ public class RadioNetworkProxy extends RadioServiceProxy { } halRequest.specifiers.add(rasInHalFormat); } - - if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).startNetworkScan_1_4( - serial, halRequest); - } else { - ((android.hardware.radio.V1_2.IRadio) mRadioProxy).startNetworkScan_1_2( - serial, halRequest); - } - } else { - android.hardware.radio.V1_1.NetworkScanRequest halRequest = - new android.hardware.radio.V1_1.NetworkScanRequest(); - halRequest.type = request.getScanType(); - halRequest.interval = request.getSearchPeriodicity(); - for (RadioAccessSpecifier ras : request.getSpecifiers()) { - android.hardware.radio.V1_1.RadioAccessSpecifier rasInHalFormat = - RILUtils.convertToHalRadioAccessSpecifier11(ras); - if (rasInHalFormat == null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - return; - } - halRequest.specifiers.add(rasInHalFormat); - } - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).startNetworkScan(serial, halRequest); + mRadioProxy.startNetworkScan_1_4(serial, halRequest); } } @@ -789,11 +749,11 @@ public class RadioNetworkProxy extends RadioServiceProxy { * @throws RemoteException */ public void stopNetworkScan(int serial) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_1)) return; + if (isEmpty()) return; if (isAidl()) { mNetworkProxy.stopNetworkScan(serial); } else { - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).stopNetworkScan(serial); + mRadioProxy.stopNetworkScan(serial); } } @@ -961,4 +921,62 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } + + /** + * Enables or disables cellular identifier disclosure transparency. + * + * @param serial Serial number of request. + * @param enable Indicates whether to enable disclosure transparency or not. + */ + public void setCellularIdentifierTransparencyEnabled(int serial, boolean enable) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setCellularIdentifierTransparencyEnabled(serial, enable); + } + // Only supported on AIDL. + } + + /** + * Checks whether cellular identifier transparency disclosure is enabled. + * + * @param serial Serial number of request. + */ + public void isCellularIdentifierTransparencyEnabled(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.isCellularIdentifierTransparencyEnabled(serial); + } + // Only supported on AIDL. + } + + /** + * Checks security algorithm update reports are enabled. + * + * @param serial Serial number of the request. + * @throws RemoteException + */ + public void isSecurityAlgorithmsUpdatedEnabled(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.isSecurityAlgorithmsUpdatedEnabled(serial); + } + // Only supported on AIDL. + } + + /** + * Enables or disables security algorithm update reports. + * + * @param serial Serial number of request. + * @param enable Indicates whether to enable or disable security algorithm update reports. + * @throws RemoteException + */ + public void setSecurityAlgorithmsUpdatedEnabled(int serial, + boolean enable) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setSecurityAlgorithmsUpdatedEnabled(serial, enable); + } + // Only supported on AIDL. + } } diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java index 0bc29583fb..ada45ec0f7 100644 --- a/src/java/com/android/internal/telephony/RadioResponse.java +++ b/src/java/com/android/internal/telephony/RadioResponse.java @@ -43,11 +43,9 @@ import android.telephony.AnomalyReporter; import android.telephony.BarringInfo; import android.telephony.CarrierRestrictionRules; import android.telephony.CellInfo; -import android.telephony.LinkCapacityEstimate; import android.telephony.ModemActivityInfo; import android.telephony.NeighboringCellInfo; import android.telephony.NetworkScanRequest; -import android.telephony.RadioAccessFamily; import android.telephony.RadioAccessSpecifier; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; @@ -103,7 +101,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param cardStatus ICC card status as defined by CardStatus in types.hal */ public void getIccCardStatusResponse(RadioResponseInfo responseInfo, CardStatus cardStatus) { - responseIccCardStatus(responseInfo, cardStatus); + responseNotSupported(responseInfo); } /** @@ -112,7 +110,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getIccCardStatusResponse_1_2(RadioResponseInfo responseInfo, android.hardware.radio.V1_2.CardStatus cardStatus) { - responseIccCardStatus_1_2(responseInfo, cardStatus); + responseNotSupported(responseInfo); } /** @@ -121,7 +119,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getIccCardStatusResponse_1_4(RadioResponseInfo responseInfo, android.hardware.radio.V1_4.CardStatus cardStatus) { - responseIccCardStatus_1_4(responseInfo, cardStatus); + responseIccCardStatus(responseInfo, cardStatus); } /** @@ -208,7 +206,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getCurrentCallsResponse(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_0.Call> calls) { - responseCurrentCalls(responseInfo, calls); + responseNotSupported(responseInfo); } /** @@ -217,7 +215,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getCurrentCallsResponse_1_2(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_2.Call> calls) { - responseCurrentCalls_1_2(responseInfo, calls); + responseCurrentCalls(responseInfo, calls); } /** @@ -301,27 +299,25 @@ public class RadioResponse extends IRadioResponse.Stub { public void getSignalStrengthResponse(RadioResponseInfo responseInfo, android.hardware.radio.V1_0.SignalStrength sigStrength) { - responseSignalStrength(responseInfo, sigStrength); + responseNotSupported(responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error * @param signalStrength Current signal strength of camped/connected cells */ - public void getSignalStrengthResponse_1_2( - RadioResponseInfo responseInfo, + public void getSignalStrengthResponse_1_2(RadioResponseInfo responseInfo, android.hardware.radio.V1_2.SignalStrength signalStrength) { - responseSignalStrength_1_2(responseInfo, signalStrength); + responseNotSupported(responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error * @param signalStrength Current signal strength of camped/connected cells */ - public void getSignalStrengthResponse_1_4( - RadioResponseInfo responseInfo, + public void getSignalStrengthResponse_1_4(RadioResponseInfo responseInfo, android.hardware.radio.V1_4.SignalStrength signalStrength) { - responseSignalStrength_1_4(responseInfo, signalStrength); + responseSignalStrength(responseInfo, signalStrength); } /** @@ -341,14 +337,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getVoiceRegistrationStateResponse(RadioResponseInfo responseInfo, VoiceRegStateResult voiceRegResponse) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, voiceRegResponse); - } - mRil.processResponseDone(rr, responseInfo, voiceRegResponse); - } + responseNotSupported(responseInfo); } /** @@ -422,14 +411,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getDataRegistrationStateResponse(RadioResponseInfo responseInfo, DataRegStateResult dataRegResponse) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, dataRegResponse); - } - mRil.processResponseDone(rr, responseInfo, dataRegResponse); - } + responseNotSupported(responseInfo); } /** @@ -439,14 +421,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getDataRegistrationStateResponse_1_2(RadioResponseInfo responseInfo, android.hardware.radio.V1_2.DataRegStateResult dataRegResponse) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, dataRegResponse); - } - mRil.processResponseDone(rr, responseInfo, dataRegResponse); - } + responseNotSupported(responseInfo); } /** @@ -584,7 +559,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void setupDataCallResponse(RadioResponseInfo responseInfo, android.hardware.radio.V1_0.SetupDataCallResult setupDataCallResult) { - responseSetupDataCall(responseInfo, setupDataCallResult); + responseNotSupported(responseInfo); } /** @@ -812,7 +787,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void startNetworkScanResponse(RadioResponseInfo responseInfo) { - responseScanStatus(responseInfo, null /*fallbackHalVersion*/); + responseNotSupported(responseInfo); } /** @@ -900,7 +875,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getDataCallListResponse(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_0.SetupDataCallResult> dataCallResultList) { - responseDataCallList(responseInfo, dataCallResultList); + responseNotSupported(responseInfo); } /** @@ -923,9 +898,6 @@ public class RadioResponse extends IRadioResponse.Stub { responseDataCallList(responseInfo, dataCallResultList); } - public void sendOemRilRequestRawResponse(RadioResponseInfo responseInfo, - ArrayList<Byte> var2) {} - /** * @param responseInfo Response info struct containing response type, serial no. and error */ @@ -998,7 +970,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void setPreferredNetworkTypeResponse(RadioResponseInfo responseInfo) { - responseVoid(responseInfo); + responseNotSupported(responseInfo); } /** @@ -1014,8 +986,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param nwType RadioPreferredNetworkType defined in types.hal */ public void getPreferredNetworkTypeResponse(RadioResponseInfo responseInfo, int nwType) { - mRil.mAllowedNetworkTypesBitmask = RadioAccessFamily.getRafFromNetworkType(nwType); - responseInts(responseInfo, RadioAccessFamily.getRafFromNetworkType(nwType)); + responseNotSupported(responseInfo); } /** @@ -1026,7 +997,6 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getPreferredNetworkTypeBitmapResponse( RadioResponseInfo responseInfo, int halRadioAccessFamilyBitmap) { - int networkTypeBitmask = RILUtils.convertHalNetworkTypeBitMask(halRadioAccessFamilyBitmap); mRil.mAllowedNetworkTypesBitmask = networkTypeBitmask; responseInts(responseInfo, networkTypeBitmask); @@ -1335,7 +1305,7 @@ public class RadioResponse extends IRadioResponse.Stub { public void getCellInfoListResponse(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_0.CellInfo> cellInfo) { - responseCellInfoList(responseInfo, cellInfo); + responseNotSupported(responseInfo); } /** @@ -1344,7 +1314,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getCellInfoListResponse_1_2(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_2.CellInfo> cellInfo) { - responseCellInfoList(responseInfo, cellInfo); + responseNotSupported(responseInfo); } /** @@ -1453,8 +1423,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error * @param result IccIoResult as defined in types.hal */ - public void iccTransmitApduLogicalChannelResponse( - RadioResponseInfo responseInfo, + public void iccTransmitApduLogicalChannelResponse(RadioResponseInfo responseInfo, android.hardware.radio.V1_0.IccIoResult result) { responseIccIo(responseInfo, result); } @@ -1502,8 +1471,10 @@ public class RadioResponse extends IRadioResponse.Stub { responseVoid(responseInfo); } - public void getHardwareConfigResponse( - RadioResponseInfo responseInfo, + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void getHardwareConfigResponse(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_0.HardwareConfig> config) { responseHardwareConfig(responseInfo, config); } @@ -1577,7 +1548,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param statusInfo LceStatusInfo indicating LCE status */ public void startLceServiceResponse(RadioResponseInfo responseInfo, LceStatusInfo statusInfo) { - responseLceStatus(responseInfo, statusInfo); + responseNotSupported(responseInfo); } /** @@ -1585,11 +1556,11 @@ public class RadioResponse extends IRadioResponse.Stub { * @param statusInfo LceStatusInfo indicating LCE status */ public void stopLceServiceResponse(RadioResponseInfo responseInfo, LceStatusInfo statusInfo) { - responseLceStatus(responseInfo, statusInfo); + responseNotSupported(responseInfo); } public void pullLceDataResponse(RadioResponseInfo responseInfo, LceDataInfo lceInfo) { - responseLceData(responseInfo, lceInfo); + responseNotSupported(responseInfo); } /** @@ -1634,26 +1605,7 @@ public class RadioResponse extends IRadioResponse.Stub { * if Length of allowed carriers list is 0, numAllowed = 0. */ public void setAllowedCarriersResponse(RadioResponseInfo responseInfo, int numAllowed) { - // The number of allowed carriers set correctly is not really useful. Even if one is - // missing, the operation has failed, as the list should be treated as a single - // configuration item. So, ignoring the value of numAllowed and considering only the - // value of the responseInfo.error. - int ret = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR; - RILRequest rr = mRil.processResponse(responseInfo); - if (rr != null) { - mRil.riljLog("setAllowedCarriersResponse - error = " + responseInfo.error); - - if (responseInfo.error == RadioError.NONE) { - ret = TelephonyManager.SET_CARRIER_RESTRICTION_SUCCESS; - sendMessageResponse(rr.mResult, ret); - } else if (responseInfo.error == RadioError.REQUEST_NOT_SUPPORTED) { - // Handle the case REQUEST_NOT_SUPPORTED as a valid response - responseInfo.error = RadioError.NONE; - ret = TelephonyManager.SET_CARRIER_RESTRICTION_NOT_SUPPORTED; - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } + responseNotSupported(responseInfo); } /** @@ -1681,13 +1633,7 @@ public class RadioResponse extends IRadioResponse.Stub { */ public void getAllowedCarriersResponse(RadioResponseInfo responseInfo, boolean allAllowed, CarrierRestrictions carriers) { - CarrierRestrictionsWithPriority carrierRestrictions = new CarrierRestrictionsWithPriority(); - carrierRestrictions.allowedCarriers = carriers.allowedCarriers; - carrierRestrictions.excludedCarriers = carriers.excludedCarriers; - carrierRestrictions.allowedCarriersPrioritized = true; - - responseCarrierRestrictions(responseInfo, allAllowed, carrierRestrictions, - SimLockMultiSimPolicy.NO_MULTISIM_POLICY); + responseNotSupported(responseInfo); } /** @@ -1696,11 +1642,36 @@ public class RadioResponse extends IRadioResponse.Stub { * @param multiSimPolicy Policy for multi-sim devices. */ public void getAllowedCarriersResponse_1_4(RadioResponseInfo responseInfo, - CarrierRestrictionsWithPriority carrierRestrictions, - int multiSimPolicy) { - // The API in IRadio 1.4 does not support the flag allAllowed, so setting it to false, so - // that values in carrierRestrictions are used. - responseCarrierRestrictions(responseInfo, false, carrierRestrictions, multiSimPolicy); + CarrierRestrictionsWithPriority carrierRestrictions, int multiSimPolicy) { + RILRequest rr = mRil.processResponse(responseInfo); + if (rr == null) { + return; + } + + int policy = CarrierRestrictionRules.MULTISIM_POLICY_NONE; + if (multiSimPolicy == SimLockMultiSimPolicy.ONE_VALID_SIM_MUST_BE_PRESENT) { + policy = CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT; + } + + int carrierRestrictionDefault = + CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED; + if (!carrierRestrictions.allowedCarriersPrioritized) { + carrierRestrictionDefault = CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED; + } + + CarrierRestrictionRules ret = CarrierRestrictionRules.newBuilder() + .setAllowedCarriers(RILUtils.convertHalCarrierList( + carrierRestrictions.allowedCarriers)) + .setExcludedCarriers(RILUtils.convertHalCarrierList( + carrierRestrictions.excludedCarriers)) + .setDefaultCarrierRestriction(carrierRestrictionDefault) + .setMultiSimPolicy(policy) + .build(); + + if (responseInfo.error == RadioError.NONE) { + sendMessageResponse(rr.mResult, ret); + } + mRil.processResponseDone(rr, responseInfo, ret); } /** @@ -1735,7 +1706,7 @@ public class RadioResponse extends IRadioResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void setSimCardPowerResponse(RadioResponseInfo responseInfo) { - responseVoid(responseInfo); + responseNotSupported(responseInfo); } /** @@ -1874,39 +1845,7 @@ public class RadioResponse extends IRadioResponse.Stub { } } - private void responseIccCardStatus(RadioResponseInfo responseInfo, CardStatus cardStatus) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - IccCardStatus iccCardStatus = RILUtils.convertHalCardStatus(cardStatus); - mRil.riljLog("responseIccCardStatus: from HIDL: " + iccCardStatus); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, iccCardStatus); - } - mRil.processResponseDone(rr, responseInfo, iccCardStatus); - } - } - - private void responseIccCardStatus_1_2(RadioResponseInfo responseInfo, - android.hardware.radio.V1_2.CardStatus cardStatus) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - IccCardStatus iccCardStatus = RILUtils.convertHalCardStatus(cardStatus.base); - IccSlotPortMapping slotPortMapping = new IccSlotPortMapping(); - slotPortMapping.mPhysicalSlotIndex = cardStatus.physicalSlotId; - iccCardStatus.mSlotPortMapping = slotPortMapping; - iccCardStatus.atr = cardStatus.atr; - iccCardStatus.iccid = cardStatus.iccid; - mRil.riljLog("responseIccCardStatus: from HIDL: " + iccCardStatus); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, iccCardStatus); - } - mRil.processResponseDone(rr, responseInfo, iccCardStatus); - } - } - - private void responseIccCardStatus_1_4(RadioResponseInfo responseInfo, + private void responseIccCardStatus(RadioResponseInfo responseInfo, android.hardware.radio.V1_4.CardStatus cardStatus) { RILRequest rr = mRil.processResponse(responseInfo); @@ -2035,52 +1974,12 @@ public class RadioResponse extends IRadioResponse.Stub { } private void responseCurrentCalls(RadioResponseInfo responseInfo, - ArrayList<android.hardware.radio.V1_0.Call> calls) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - int num = calls.size(); - ArrayList<DriverCall> dcCalls = new ArrayList<DriverCall>(num); - DriverCall dc; - - for (int i = 0; i < num; i++) { - dc = RILUtils.convertToDriverCall(calls.get(i)); - - dcCalls.add(dc); - - if (dc.isVoicePrivacy) { - mRil.mVoicePrivacyOnRegistrants.notifyRegistrants(); - mRil.riljLog("InCall VoicePrivacy is enabled"); - } else { - mRil.mVoicePrivacyOffRegistrants.notifyRegistrants(); - mRil.riljLog("InCall VoicePrivacy is disabled"); - } - } - - Collections.sort(dcCalls); - - if ((num == 0) && mRil.mTestingEmergencyCall.getAndSet(false)) { - if (mRil.mEmergencyCallbackModeRegistrant != null) { - mRil.riljLog("responseCurrentCalls: call ended, testing emergency call," - + " notify ECM Registrants"); - mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant(); - } - } - - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, dcCalls); - } - mRil.processResponseDone(rr, responseInfo, dcCalls); - } - } - - private void responseCurrentCalls_1_2(RadioResponseInfo responseInfo, ArrayList<android.hardware.radio.V1_2.Call> calls) { RILRequest rr = mRil.processResponse(responseInfo); if (rr != null) { int num = calls.size(); - ArrayList<DriverCall> dcCalls = new ArrayList<DriverCall>(num); + ArrayList<DriverCall> dcCalls = new ArrayList<>(num); DriverCall dc; for (int i = 0; i < num; i++) { @@ -2155,6 +2054,15 @@ public class RadioResponse extends IRadioResponse.Stub { } } + private void responseNotSupported(RadioResponseInfo responseInfo) { + RILRequest rr = mRil.processResponse(responseInfo); + if (rr != null) { + mRil.riljLog(RILUtils.requestToString(rr.mRequest) + "not supported on IRadio < 1.4"); + responseInfo.error = RadioError.REQUEST_NOT_SUPPORTED; + mRil.processResponseDone(rr, responseInfo, null); + } + } + private void responseVoid(RadioResponseInfo responseInfo) { RILRequest rr = mRil.processResponse(responseInfo); @@ -2301,34 +2209,6 @@ public class RadioResponse extends IRadioResponse.Stub { private void responseSignalStrength( RadioResponseInfo responseInfo, - android.hardware.radio.V1_0.SignalStrength signalStrength) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - private void responseSignalStrength_1_2( - RadioResponseInfo responseInfo, - android.hardware.radio.V1_2.SignalStrength signalStrength) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - private void responseSignalStrength_1_4( - RadioResponseInfo responseInfo, android.hardware.radio.V1_4.SignalStrength signalStrength) { RILRequest rr = mRil.processResponse(responseInfo); @@ -2696,69 +2576,6 @@ public class RadioResponse extends IRadioResponse.Stub { } } - private void responseLceStatus(RadioResponseInfo responseInfo, LceStatusInfo statusInfo) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - ArrayList<Integer> ret = new ArrayList<>(); - ret.add(statusInfo.lceStatus); - ret.add(Byte.toUnsignedInt(statusInfo.actualIntervalMs)); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - private void responseLceData(RadioResponseInfo responseInfo, LceDataInfo lceInfo) { - RILRequest rr = mRil.processResponse(responseInfo); - - if (rr != null) { - List<LinkCapacityEstimate> ret = RILUtils.convertHalLceData(lceInfo); - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - private void responseCarrierRestrictions(RadioResponseInfo responseInfo, boolean allAllowed, - CarrierRestrictionsWithPriority carriers, int multiSimPolicy) { - RILRequest rr = mRil.processResponse(responseInfo); - if (rr == null) { - return; - } - CarrierRestrictionRules ret; - - if (allAllowed) { - ret = CarrierRestrictionRules.newBuilder().setAllCarriersAllowed().build(); - } else { - int policy = CarrierRestrictionRules.MULTISIM_POLICY_NONE; - if (multiSimPolicy == SimLockMultiSimPolicy.ONE_VALID_SIM_MUST_BE_PRESENT) { - policy = CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT; - } - - int carrierRestrictionDefault = - CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED; - if (!carriers.allowedCarriersPrioritized) { - carrierRestrictionDefault = - CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED; - } - - ret = CarrierRestrictionRules.newBuilder() - .setAllowedCarriers(RILUtils.convertHalCarrierList(carriers.allowedCarriers)) - .setExcludedCarriers(RILUtils.convertHalCarrierList(carriers.excludedCarriers)) - .setDefaultCarrierRestriction(carrierRestrictionDefault) - .setMultiSimPolicy(policy) - .build(); - } - - if (responseInfo.error == RadioError.NONE) { - sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - /** * @param responseInfo Response info struct containing response type, serial number and error. */ diff --git a/src/java/com/android/internal/telephony/RadioServiceProxy.java b/src/java/com/android/internal/telephony/RadioServiceProxy.java index 4257327330..02fc751484 100644 --- a/src/java/com/android/internal/telephony/RadioServiceProxy.java +++ b/src/java/com/android/internal/telephony/RadioServiceProxy.java @@ -19,13 +19,13 @@ package com.android.internal.telephony; import android.os.RemoteException; /** - * A holder for IRadio services. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get the AIDL service and call the AIDL implementations of the HAL APIs. + * A holder for IRadio services. + * Use getHidl to get the HIDL IRadio service or getAidl to get the corresponding AIDL service. */ public abstract class RadioServiceProxy { boolean mIsAidl; HalVersion mHalVersion = RIL.RADIO_HAL_VERSION_UNKNOWN; - volatile android.hardware.radio.V1_0.IRadio mRadioProxy = null; + volatile android.hardware.radio.V1_4.IRadio mRadioProxy = null; /** * Whether RadioServiceProxy is an AIDL or HIDL implementation @@ -40,7 +40,7 @@ public abstract class RadioServiceProxy { * @param halVersion Radio HAL version * @param radio IRadio implementation */ - public void setHidl(HalVersion halVersion, android.hardware.radio.V1_0.IRadio radio) { + public void setHidl(HalVersion halVersion, android.hardware.radio.V1_4.IRadio radio) { mHalVersion = halVersion; mRadioProxy = radio; mIsAidl = false; @@ -50,7 +50,7 @@ public abstract class RadioServiceProxy { * Get the HIDL implementation of RadioServiceProxy * @return IRadio implementation */ - public android.hardware.radio.V1_0.IRadio getHidl() { + public android.hardware.radio.V1_4.IRadio getHidl() { return mRadioProxy; } diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index 7c8ee7b6ea..5265692167 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -16,22 +16,17 @@ package com.android.internal.telephony; -import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED; - -import android.os.AsyncResult; -import android.os.Message; import android.os.RemoteException; import android.telephony.CarrierRestrictionRules; import android.telephony.ImsiEncryptionInfo; import android.telephony.Rlog; -import android.telephony.TelephonyManager; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.SimPhonebookRecord; /** - * A holder for IRadioSim. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioSim and call the AIDL implementations of the HAL APIs. + * A holder for IRadioSim. + * Use getAidl to get IRadioSim and call the AIDL implementations of the HAL APIs. */ public class RadioSimProxy extends RadioServiceProxy { private static final String TAG = "RadioSimProxy"; @@ -160,10 +155,8 @@ public class RadioSimProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { mSimProxy.getAllowedCarriers(serial); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).getAllowedCarriers_1_4(serial); } else { - mRadioProxy.getAllowedCarriers(serial); + mRadioProxy.getAllowedCarriers_1_4(serial); } } @@ -521,11 +514,10 @@ public class RadioSimProxy extends RadioServiceProxy { * Call IRadioSim#setAllowedCarriers * @param serial Serial number of request * @param carrierRestrictionRules Allowed carriers - * @param result Result to return in case of error * @throws RemoteException */ - public void setAllowedCarriers(int serial, CarrierRestrictionRules carrierRestrictionRules, - Message result) throws RemoteException { + public void setAllowedCarriers(int serial, CarrierRestrictionRules carrierRestrictionRules) + throws RemoteException { if (isEmpty()) return; if (isAidl()) { // Prepare structure with allowed list, excluded list and priority @@ -541,7 +533,7 @@ public class RadioSimProxy extends RadioServiceProxy { mSimProxy.setAllowedCarriers(serial, carrierRestrictions, RILUtils.convertToHalSimLockMultiSimPolicyAidl( carrierRestrictionRules.getMultiSimPolicy())); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_4)) { + } else { // Prepare structure with allowed list, excluded list and priority android.hardware.radio.V1_4.CarrierRestrictionsWithPriority carrierRestrictions = new android.hardware.radio.V1_4.CarrierRestrictionsWithPriority(); @@ -552,35 +544,9 @@ public class RadioSimProxy extends RadioServiceProxy { carrierRestrictions.allowedCarriersPrioritized = (carrierRestrictionRules.getDefaultCarrierRestriction() == CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED); - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).setAllowedCarriers_1_4( - serial, carrierRestrictions, RILUtils.convertToHalSimLockMultiSimPolicy( + mRadioProxy.setAllowedCarriers_1_4(serial, carrierRestrictions, + RILUtils.convertToHalSimLockMultiSimPolicy( carrierRestrictionRules.getMultiSimPolicy())); - } else { - boolean isAllCarriersAllowed = carrierRestrictionRules.isAllCarriersAllowed(); - boolean supported = (isAllCarriersAllowed - || (carrierRestrictionRules.getExcludedCarriers().isEmpty() - && (carrierRestrictionRules.getDefaultCarrierRestriction() - == CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED))) - && (RILUtils.convertToHalSimLockMultiSimPolicy( - carrierRestrictionRules.getMultiSimPolicy()) - == android.hardware.radio.V1_4.SimLockMultiSimPolicy.NO_MULTISIM_POLICY); - - if (!supported) { - // Feature is not supported by IRadio interface - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - return; - } - - // Prepare structure with allowed list - android.hardware.radio.V1_0.CarrierRestrictions carrierRestrictions = - new android.hardware.radio.V1_0.CarrierRestrictions(); - carrierRestrictions.allowedCarriers = RILUtils.convertToHalCarrierRestrictionList( - carrierRestrictionRules.getAllowedCarriers()); - mRadioProxy.setAllowedCarriers(serial, isAllCarriersAllowed, carrierRestrictions); } } @@ -592,7 +558,7 @@ public class RadioSimProxy extends RadioServiceProxy { */ public void setCarrierInfoForImsiEncryption(int serial, ImsiEncryptionInfo imsiEncryptionInfo) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_1)) return; + if (isEmpty()) return; if (isAidl()) { android.hardware.radio.sim.ImsiEncryptionInfo halImsiInfo = new android.hardware.radio.sim.ImsiEncryptionInfo(); @@ -635,8 +601,7 @@ public class RadioSimProxy extends RadioServiceProxy { halImsiInfo.carrierKey.add(Byte.valueOf(b)); } - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).setCarrierInfoForImsiEncryption( - serial, halImsiInfo); + mRadioProxy.setCarrierInfoForImsiEncryption(serial, halImsiInfo); } } @@ -681,35 +646,16 @@ public class RadioSimProxy extends RadioServiceProxy { * Call IRadioSim#setSimCardPower * @param serial Serial number of request * @param state SIM state (power down, power up, pass through) - * @param result Result to return in case of error * @throws RemoteException */ - public void setSimCardPower(int serial, int state, Message result) throws RemoteException { + public void setSimCardPower(int serial, int state) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mSimProxy.setSimCardPower(serial, state); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).setSimCardPower_1_6(serial, state); - } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_1)) { - ((android.hardware.radio.V1_1.IRadio) mRadioProxy).setSimCardPower_1_1(serial, state); - } else { - switch (state) { - case TelephonyManager.CARD_POWER_DOWN: { - mRadioProxy.setSimCardPower(serial, false); - break; - } - case TelephonyManager.CARD_POWER_UP: { - mRadioProxy.setSimCardPower(serial, true); - break; - } - default: { - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - } + } else { + mRadioProxy.setSimCardPower_1_1(serial, state); } } diff --git a/src/java/com/android/internal/telephony/RadioVoiceProxy.java b/src/java/com/android/internal/telephony/RadioVoiceProxy.java index 7f46424485..e57a61d81c 100644 --- a/src/java/com/android/internal/telephony/RadioVoiceProxy.java +++ b/src/java/com/android/internal/telephony/RadioVoiceProxy.java @@ -24,8 +24,8 @@ import android.telephony.emergency.EmergencyNumber; import java.util.ArrayList; /** - * A holder for IRadioVoice. Use getHidl to get IRadio 1.0 and call the HIDL implementations or - * getAidl to get IRadioVoice and call the AIDL implementations of the HAL APIs. + * A holder for IRadioVoice. + * Use getAidl to get IRadioVoice and call the AIDL implementations of the HAL APIs. */ public class RadioVoiceProxy extends RadioServiceProxy { private static final String TAG = "RadioVoiceProxy"; @@ -153,7 +153,7 @@ public class RadioVoiceProxy extends RadioServiceProxy { public void emergencyDial(int serial, String address, EmergencyNumber emergencyNumberInfo, boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo) throws RemoteException { - if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_4)) return; + if (isEmpty()) return; if (isAidl()) { mVoiceProxy.emergencyDial(serial, RILUtils.convertToHalDialAidl(address, clirMode, uusInfo), @@ -177,7 +177,7 @@ public class RadioVoiceProxy extends RadioServiceProxy { emergencyNumberInfo.getEmergencyNumberSourceBitmask() == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } else { - ((android.hardware.radio.V1_4.IRadio) mRadioProxy).emergencyDial(serial, + mRadioProxy.emergencyDial(serial, RILUtils.convertToHalDial(address, clirMode, uusInfo), emergencyNumberInfo.getEmergencyServiceCategoryBitmaskInternalDial(), emergencyNumberInfo.getEmergencyUrns() != null diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 5df9f0890e..04f5c083ba 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -86,6 +86,8 @@ import android.widget.TextView; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; +import com.android.internal.telephony.analytics.TelephonyAnalytics; +import com.android.internal.telephony.analytics.TelephonyAnalytics.SmsMmsAnalytics; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -1008,6 +1010,16 @@ public abstract class SMSDispatcher extends Handler { protected abstract boolean shouldBlockSmsForEcbm(); /** + * Notifies the {@link SmsDispatchersController} that sending MO SMS is failed. + * + * @param tracker holds the SMS message to be sent + */ + protected void notifySmsSentFailedToEmergencyStateTracker(SmsTracker tracker) { + mSmsDispatchersController.notifySmsSentFailedToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); + } + + /** * Called when SMS send completes. Broadcasts a sentIntent on success. * On failure, either sets up retries or broadcasts a sentIntent with * the failure in the result code. @@ -1039,6 +1051,8 @@ public abstract class SMSDispatcher extends Handler { } tracker.onSent(mContext); mPhone.notifySmsSent(tracker.mDestAddress); + mSmsDispatchersController.notifySmsSentToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); mPhone.getSmsStats().onOutgoingSms( tracker.mImsRetry > 0 /* isOverIms */, @@ -1048,6 +1062,19 @@ public abstract class SMSDispatcher extends Handler { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + tracker.mImsRetry > 0 /* isOverIms */, + SmsManager.RESULT_ERROR_NONE + ); + } + } + } + } else { if (DBG) { Rlog.d(TAG, "SMS send failed " @@ -1076,6 +1103,7 @@ public abstract class SMSDispatcher extends Handler { // if sms over IMS is not supported on data and voice is not available... if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker(tracker); mPhone.getSmsStats().onOutgoingSms( tracker.mImsRetry > 0 /* isOverIms */, SmsConstants.FORMAT_3GPP2.equals(getFormat()), @@ -1084,6 +1112,19 @@ public abstract class SMSDispatcher extends Handler { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + tracker.mImsRetry > 0 /* isOverIms */, + getNotInServiceError(ss) + ); + } + } + } + } else if (error == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY && tracker.mRetryCount < getMaxSmsRetryCount()) { // Retry after a delay if needed. @@ -1107,9 +1148,23 @@ public abstract class SMSDispatcher extends Handler { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + tracker.mImsRetry > 0 /* isOverIms */, + SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY + ); + } + } + } + } else { int errorCode = (smsResponse != null) ? smsResponse.mErrorCode : NO_ERROR_CODE; tracker.onFailed(mContext, error, errorCode); + notifySmsSentFailedToEmergencyStateTracker(tracker); mPhone.getSmsStats().onOutgoingSms( tracker.mImsRetry > 0 /* isOverIms */, SmsConstants.FORMAT_3GPP2.equals(getFormat()), @@ -1119,6 +1174,17 @@ public abstract class SMSDispatcher extends Handler { tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + tracker.mImsRetry > 0 /* isOverIms */, + error); + } + } + } } } } @@ -2323,6 +2389,7 @@ public abstract class SMSDispatcher extends Handler { int errorCode) { for (SmsTracker tracker : trackers) { tracker.onFailed(mContext, error, errorCode); + notifySmsSentFailedToEmergencyStateTracker(tracker); } if (trackers.length > 0) { // This error occurs before the SMS is sent. Make an assumption if it would have @@ -2335,6 +2402,17 @@ public abstract class SMSDispatcher extends Handler { trackers[0].mMessageId, trackers[0].isFromDefaultSmsApplication(mContext), trackers[0].getInterval()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onOutgoingSms( + isIms(), + error); + } + } + } } } diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 8a4967085f..d19e4cb359 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -94,10 +94,15 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; +import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhone; +import com.android.internal.telephony.metrics.RadioPowerStateStats; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.satellite.NtnCapabilityResolver; +import com.android.internal.telephony.satellite.SatelliteController; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; @@ -623,7 +628,8 @@ public class ServiceStateTracker extends Handler { */ private AccessNetworksManagerCallback mAccessNetworksManagerCallback = null; - public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) { + public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci, + FeatureFlags featureFlags) { mNitzState = TelephonyComponentFactory.getInstance() .inject(NitzStateMachine.class.getName()) .makeNitzStateMachine(phone); @@ -685,7 +691,7 @@ public class ServiceStateTracker extends Handler { // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.Global.getInt(mCr, Settings.Global.AIRPLANE_MODE_ON, 0); int enableCellularOnBoot = Settings.Global.getInt(mCr, - Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1); + Settings.Global.ENABLE_CELLULAR_ON_BOOT, getDefaultEnableCellularOnBoot()); mDesiredPowerState = (enableCellularOnBoot > 0) && ! (airplaneMode > 0); if (!mDesiredPowerState) { mRadioPowerOffReasons.add(TelephonyManager.RADIO_POWER_REASON_USER); @@ -708,7 +714,7 @@ public class ServiceStateTracker extends Handler { mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null); updatePhoneType(); - mCSST = new CarrierServiceStateTracker(phone, this); + mCSST = new CarrierServiceStateTracker(phone, this, featureFlags); registerForNetworkAttached(mCSST, CarrierServiceStateTracker.CARRIER_EVENT_VOICE_REGISTRATION, null); @@ -749,6 +755,11 @@ public class ServiceStateTracker extends Handler { } } + private int getDefaultEnableCellularOnBoot() { + return mPhone.getContext().getResources().getBoolean( + R.bool.config_enable_cellular_on_boot_default) ? 1 : 0; + } + @VisibleForTesting public void updatePhoneType() { @@ -1325,6 +1336,8 @@ public class ServiceStateTracker extends Handler { break; case EVENT_RADIO_STATE_CHANGED: + RadioPowerStateStats.onRadioStateChanged(mCi.getRadioState()); + // fall through, the code above only logs metrics when radio state changes case EVENT_PHONE_TYPE_SWITCHED: if(!mPhone.isPhoneTypeGsm() && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { @@ -1937,16 +1950,15 @@ public class ServiceStateTracker extends Handler { err = ((CommandException)(ar.exception)).getCommandError(); } - if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_ON) { - log("handlePollStateResult: Invalid response due to radio off or unavailable. " - + "Set ServiceState to out of service."); - pollStateInternal(false); - return; - } - if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { - loge("handlePollStateResult: RIL returned RADIO_NOT_AVAILABLE when radio is on."); - cancelPollState(); + loge("handlePollStateResult: RIL returned RADIO_NOT_AVAILABLE."); + if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { + cancelPollState(); + } else { + handlePollStateInternalForRadioOffOrUnavailable( + mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF); + pollStateDone(); + } return; } @@ -3303,42 +3315,17 @@ public class ServiceStateTracker extends Handler { private void pollStateInternal(boolean modemTriggered) { mPollingContext = new int[1]; - NetworkRegistrationInfo nri; log("pollState: modemTriggered=" + modemTriggered + ", radioState=" + mCi.getRadioState()); switch (mCi.getRadioState()) { case TelephonyManager.RADIO_POWER_UNAVAILABLE: - // Preserve the IWLAN registration state, because that should not be affected by - // radio availability. - nri = mNewSS.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(false); - // Add the IWLAN registration info back to service state. - if (nri != null) { - mNewSS.addNetworkRegistrationInfo(nri); - } - mPhone.getSignalStrengthController().setSignalStrengthDefaultValues(); - mLastNitzData = null; - mNitzState.handleNetworkUnavailable(); + handlePollStateInternalForRadioOffOrUnavailable(false); pollStateDone(); break; case TelephonyManager.RADIO_POWER_OFF: - // Preserve the IWLAN registration state, because that should not be affected by - // radio availability. - nri = mNewSS.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(true); - // Add the IWLAN registration info back to service state. - if (nri != null) { - mNewSS.addNetworkRegistrationInfo(nri); - } - mPhone.getSignalStrengthController().setSignalStrengthDefaultValues(); - mLastNitzData = null; - mNitzState.handleNetworkUnavailable(); + handlePollStateInternalForRadioOffOrUnavailable(true); // Don't poll when device is shutting down or the poll was not modemTriggered // (they sent us new radio data) and the current network is not IWLAN if (mDeviceShuttingDown || @@ -3382,6 +3369,21 @@ public class ServiceStateTracker extends Handler { } } + private void handlePollStateInternalForRadioOffOrUnavailable(boolean radioOff) { + // Preserve the IWLAN registration state, which should not be affected by radio availability + NetworkRegistrationInfo nri = mNewSS.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + mNewSS.setOutOfService(radioOff); + // Add the IWLAN registration info back to service state. + if (nri != null) { + mNewSS.addNetworkRegistrationInfo(nri); + } + mPhone.getSignalStrengthController().setSignalStrengthDefaultValues(); + mLastNitzData = null; + mNitzState.handleNetworkUnavailable(); + } + /** * Get the highest-priority CellIdentity for a provided ServiceState. * @@ -4968,6 +4970,10 @@ public class ServiceStateTracker extends Handler { */ public void powerOffRadioSafely() { synchronized (this) { + SatelliteController.getInstance().onCellularRadioPowerOffRequested(); + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + EmergencyStateTracker.getInstance().onCellularRadioPowerOffRequested(); + } if (!mPendingRadioPowerOffAfterDataOff) { // hang up all active voice calls first if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { @@ -5053,7 +5059,6 @@ public class ServiceStateTracker extends Handler { } mCi.setRadioPower(false, obtainMessage(EVENT_RADIO_POWER_OFF_DONE)); - } /** Cancel a pending (if any) pollState() operation */ diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index 8c35e571f5..b11d7e564f 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -30,6 +30,7 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; import android.telephony.AccessNetworkConstants; +import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; import android.telephony.CellIdentity; import android.telephony.CellIdentityLte; @@ -61,7 +62,9 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeSet; +import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.PatternSyntaxException; /** @@ -99,6 +102,7 @@ public class SignalStrengthController extends Handler { private static final int EVENT_POLL_SIGNAL_STRENGTH = 7; private static final int EVENT_SIGNAL_STRENGTH_UPDATE = 8; private static final int EVENT_POLL_SIGNAL_STRENGTH_DONE = 9; + private static final int EVENT_SERVICE_STATE_CHANGED = 10; @NonNull private final Phone mPhone; @@ -144,6 +148,8 @@ public class SignalStrengthController extends Handler { @NonNull private final LocalLog mLocalLog = new LocalLog(64); + private final AtomicBoolean mNTNConnected = new AtomicBoolean(false); + public SignalStrengthController(@NonNull Phone phone) { mPhone = phone; mCi = mPhone.mCi; @@ -159,6 +165,8 @@ public class SignalStrengthController extends Handler { ccm.registerCarrierConfigChangeListener(this::post, (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged(slotIndex)); + + mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); } @Override @@ -271,6 +279,11 @@ public class SignalStrengthController extends Handler { break; } + case EVENT_SERVICE_STATE_CHANGED: { + onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result); + break; + } + default: log("Unhandled message with number: " + msg.what); break; @@ -351,7 +364,7 @@ public class SignalStrengthController extends Handler { List<SubscriptionInfo> subInfoList = SubscriptionManagerService.getInstance() .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(), - mPhone.getContext().getAttributionTag()); + mPhone.getContext().getAttributionTag(), true/*isForAllProfile*/); if (!ArrayUtils.isEmpty(subInfoList)) { for (SubscriptionInfo info : subInfoList) { @@ -384,9 +397,10 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY); if (gsmRssiThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, gsmRssiThresholds, + AccessNetworkThresholds.GERAN, AccessNetworkConstants.AccessNetworkType.GERAN, true)); } @@ -395,45 +409,54 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY); if (wcdmaRscpThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP, wcdmaRscpThresholds, + AccessNetworkThresholds.UTRAN, AccessNetworkConstants.AccessNetworkType.UTRAN, true)); } - int lteMeasurementEnabled = mCarrierConfig.getInt(CarrierConfigManager - .KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, CellSignalStrengthLte.USE_RSRP); - int[] lteRsrpThresholds = mCarrierConfig.getIntArray( - CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY); + int lteMeasurementEnabled = mCarrierConfig.getInt(isUsingNonTerrestrialNetwork() + ? CarrierConfigManager.KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT + : CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, + CellSignalStrengthLte.USE_RSRP); + int[] lteRsrpThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork() + ? CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY + : CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY); if (lteRsrpThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP, lteRsrpThresholds, + AccessNetworkThresholds.EUTRAN_RSRP, AccessNetworkConstants.AccessNetworkType.EUTRAN, (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRP) != 0)); } if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { - int[] lteRsrqThresholds = mCarrierConfig.getIntArray( + int[] lteRsrqThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork() + ? CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY : CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY); if (lteRsrqThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, lteRsrqThresholds, + AccessNetworkThresholds.EUTRAN_RSRQ, AccessNetworkConstants.AccessNetworkType.EUTRAN, (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRQ) != 0)); } - int[] lteRssnrThresholds = mCarrierConfig.getIntArray( + int[] lteRssnrThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork() + ? CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY : CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY); if (lteRssnrThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR, lteRssnrThresholds, + AccessNetworkThresholds.EUTRAN_RSSNR, AccessNetworkConstants.AccessNetworkType.EUTRAN, (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSSNR) != 0)); } @@ -444,9 +467,10 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY); if (nrSsrsrpThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, nrSsrsrpThresholds, + AccessNetworkThresholds.NGRAN_SSRSRP, AccessNetworkConstants.AccessNetworkType.NGRAN, (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSRSRP) != 0)); } @@ -455,9 +479,10 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY); if (nrSsrsrqThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ, nrSsrsrqThresholds, + AccessNetworkThresholds.NGRAN_SSRSRQ, AccessNetworkConstants.AccessNetworkType.NGRAN, (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSRSRQ) != 0)); } @@ -466,9 +491,10 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY); if (nrSssinrThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR, nrSssinrThresholds, + AccessNetworkThresholds.NGRAN_SSSINR, AccessNetworkConstants.AccessNetworkType.NGRAN, (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSSINR) != 0)); } @@ -477,9 +503,10 @@ public class SignalStrengthController extends Handler { CarrierConfigManager.KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY); if (wcdmaEcnoThresholds != null) { signalThresholdInfos.add( - createSignalThresholdsInfo( + validateAndCreateSignalThresholdInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO, wcdmaEcnoThresholds, + AccessNetworkThresholds.UTRAN_ECNO, AccessNetworkConstants.AccessNetworkType.UTRAN, false)); } @@ -1150,6 +1177,45 @@ public class SignalStrengthController extends Handler { } /** + * Validate the provided signal {@code thresholds} info and fall back to use the + * {@code defaultThresholds} and report anomaly if invalid to prevent crashing Phone. + */ + private static SignalThresholdInfo validateAndCreateSignalThresholdInfo( + int measurementType, @NonNull int[] thresholds, @NonNull int[] defaultThresholds, + int ran, boolean isEnabled) { + SignalThresholdInfo signalThresholdInfo; + try { + signalThresholdInfo = new SignalThresholdInfo.Builder() + .setSignalMeasurementType(measurementType) + .setThresholds(thresholds) + .setRadioAccessNetworkType(ran) + .setIsEnabled(isEnabled) + .build(); + // TODO(b/295236831): only catch IAE when phone global exception handler is introduced. + // Although SignalThresholdInfo only throws IAE for invalid carrier configs, we catch + // all exception to prevent crashing phone before global exception handler is available. + } catch (Exception e) { + signalThresholdInfo = new SignalThresholdInfo.Builder() + .setSignalMeasurementType(measurementType) + .setThresholds(defaultThresholds) + .setRadioAccessNetworkType(ran) + .setIsEnabled(isEnabled) + .build(); + + AnomalyReporter.reportAnomaly( + UUID.fromString("28232bc4-78ff-447e-b597-7c054c802407"), + "Invalid parameter to generate SignalThresholdInfo: " + + "measurementType=" + measurementType + + ", thresholds=" + Arrays.toString(thresholds) + + ", RAN=" + ran + + ", isEnabled=" + isEnabled + + ". Replaced with default thresholds: " + Arrays.toString( + defaultThresholds)); + } + return signalThresholdInfo; + } + + /** * dBm thresholds that correspond to changes in signal strength indications. */ private static final class AccessNetworkThresholds { @@ -1272,6 +1338,25 @@ public class SignalStrengthController extends Handler { }; } + private void onServiceStateChanged(ServiceState state) { + if (state.getState() != ServiceState.STATE_IN_SERVICE) { + return; + } + + if (mNTNConnected.get() != state.isUsingNonTerrestrialNetwork()) { + log("onServiceStateChanged: update it to " + state.isUsingNonTerrestrialNetwork()); + updateReportingCriteria(); + mNTNConnected.set(state.isUsingNonTerrestrialNetwork()); + } + } + + private boolean isUsingNonTerrestrialNetwork() { + if (mPhone.getServiceState() == null) { + return false; + } + return mPhone.getServiceState().isUsingNonTerrestrialNetwork(); + } + private static void log(String msg) { if (DBG) Rlog.d(TAG, msg); } diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java index ecd62765a1..7fc499e6a0 100644 --- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java @@ -31,6 +31,8 @@ import android.os.UserManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; +import com.android.internal.telephony.analytics.TelephonyAnalytics; +import com.android.internal.telephony.analytics.TelephonyAnalytics.SmsMmsAnalytics; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.gsm.GsmInboundSmsHandler; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -242,6 +244,14 @@ public class SmsBroadcastUndelivered { if (phone != null) { phone.getSmsStats().onDroppedIncomingMultipartSms(message.mIs3gpp2, rows, message.mMessageCount); + TelephonyAnalytics telephonyAnalytics = phone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + SmsMmsAnalytics smsMmsAnalytics = + telephonyAnalytics.getSmsMmsAnalytics(); + if (smsMmsAnalytics != null) { + smsMmsAnalytics.onDroppedIncomingMultipartSms(); + } + } } } } diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index d2dfcacdfb..8795840e9a 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -45,16 +45,20 @@ import android.telephony.ServiceState; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; import android.text.TextUtils; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.SomeArgs; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; import com.android.internal.telephony.domainselection.DomainSelectionConnection; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; +import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.GsmInboundSmsHandler; import com.android.internal.telephony.gsm.GsmSMSDispatcher; import com.android.telephony.Rlog; @@ -62,8 +66,10 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; /** @@ -94,6 +100,15 @@ public class SmsDispatchersController extends Handler { /** InboundSmsHandler exited WaitingState */ protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; + /** Called when SMS should be sent using AP domain selection. */ + private static final int EVENT_SEND_SMS_USING_DOMAIN_SELECTION = 18; + + /** Called when SMS is completely sent using AP domain selection regardless of the result. */ + private static final int EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION = 19; + + /** Called when AP domain selection is abnormally terminated. */ + private static final int EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY = 20; + /** Delete any partial message segments after being IN_SERVICE for 1 day. */ private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; /** Constant for invalid time */ @@ -117,6 +132,7 @@ public class SmsDispatchersController extends Handler { private final SmsUsageMonitor mUsageMonitor; private final CommandsInterface mCi; private final Context mContext; + private final @NonNull FeatureFlags mFeatureFlags; /** true if IMS is registered and sms is supported, false otherwise.*/ private boolean mIms = false; @@ -183,7 +199,7 @@ public class SmsDispatchersController extends Handler { }; /** Stores the sending SMS information for a pending request. */ - private class PendingRequest { + private static class PendingRequest { public static final int TYPE_DATA = 1; public static final int TYPE_TEXT = 2; public static final int TYPE_MULTIPART_TEXT = 3; @@ -310,13 +326,18 @@ public class SmsDispatchersController extends Handler { @Override public void onSelectionTerminated(@DisconnectCauses int cause) { - notifyDomainSelectionTerminated(this); + logd("onSelectionTerminated: emergency=" + mEmergency + ", cause=" + cause); + // This callback is invoked by another thread, so this operation is posted and handled + // through the execution flow of SmsDispatchersController. + SmsDispatchersController.this.sendMessage( + obtainMessage(EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY, this)); } } /** Manages the domain selection connections: MO SMS or emergency SMS. */ private DomainSelectionConnectionHolder mDscHolder; private DomainSelectionConnectionHolder mEmergencyDscHolder; + private EmergencyStateTracker mEmergencyStateTracker; /** * Puts a delivery pending tracker to the map based on the format. @@ -332,13 +353,13 @@ public class SmsDispatchersController extends Handler { } public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, - SmsUsageMonitor usageMonitor) { - this(phone, storageMonitor, usageMonitor, phone.getLooper()); + SmsUsageMonitor usageMonitor, @NonNull FeatureFlags featureFlags) { + this(phone, storageMonitor, usageMonitor, phone.getLooper(), featureFlags); } @VisibleForTesting public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, - SmsUsageMonitor usageMonitor, Looper looper) { + SmsUsageMonitor usageMonitor, Looper looper, @NonNull FeatureFlags featureFlags) { super(looper); Rlog.d(TAG, "SmsDispatchersController created"); @@ -346,6 +367,7 @@ public class SmsDispatchersController extends Handler { mContext = phone.getContext(); mUsageMonitor = usageMonitor; mCi = phone.mCi; + mFeatureFlags = featureFlags; mPhone = phone; // Create dispatchers, inbound SMS handlers and @@ -447,7 +469,36 @@ public class SmsDispatchersController extends Handler { mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); resetPartialSegmentWaitTimer(); break; - + case EVENT_SEND_SMS_USING_DOMAIN_SELECTION: { + SomeArgs args = (SomeArgs) msg.obj; + DomainSelectionConnectionHolder holder = + (DomainSelectionConnectionHolder) args.arg1; + PendingRequest request = (PendingRequest) args.arg2; + String logTag = (String) args.arg3; + try { + handleSendSmsUsingDomainSelection(holder, request, logTag); + } finally { + args.recycle(); + } + break; + } + case EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION: { + SomeArgs args = (SomeArgs) msg.obj; + String destAddr = (String) args.arg1; + Long messageId = (Long) args.arg2; + Boolean success = (Boolean) args.arg3; + try { + handleSmsSentCompletedUsingDomainSelection(destAddr, messageId, success); + } finally { + args.recycle(); + } + break; + } + case EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY: { + handleDomainSelectionTerminatedAbnormally( + (DomainSelectionConnectionHolder) msg.obj); + break; + } default: if (isCdmaMo()) { mCdmaDispatcher.handleMessage(msg); @@ -701,7 +752,7 @@ public class SmsDispatchersController extends Handler { boolean retryUsingImsService = false; if (!tracker.mUsesImsServiceForIms) { - if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + if (isSmsDomainSelectionEnabled()) { DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); // If the DomainSelectionConnection is not available, @@ -756,6 +807,8 @@ public class SmsDispatchersController extends Handler { // should never come here... Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!"); tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); return; } String scAddr = (String) map.get("scAddr"); @@ -763,6 +816,8 @@ public class SmsDispatchersController extends Handler { if (destAddr == null) { Rlog.e(TAG, "sendRetrySms failed due to null destAddr"); tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); return; } @@ -803,6 +858,8 @@ public class SmsDispatchersController extends Handler { + "scAddr: %s, " + "destPort: %s", scAddr, map.get("destPort"))); tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker( + tracker.mDestAddress, tracker.mMessageId); return; } // replace old smsc and pdu with newly encoded ones @@ -889,6 +946,16 @@ public class SmsDispatchersController extends Handler { } /** + * Checks whether the SMS domain selection is enabled or not. + * + * @return {@code true} if the SMS domain selection is enabled, {@code false} otherwise. + */ + private boolean isSmsDomainSelectionEnabled() { + return mFeatureFlags.smsDomainSelectionEnabled() + && mDomainSelectionResolverProxy.isDomainSelectionSupported(); + } + + /** * Determines whether or not to use CDMA format for MO SMS when the domain selection uses. * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on * IMS SMS format, otherwise format is based on current phone type. @@ -929,7 +996,6 @@ public class SmsDispatchersController extends Handler { private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) { DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency); DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; - boolean created = false; if (connection == null) { connection = mDomainSelectionResolverProxy.getDomainSelectionConnection( @@ -940,8 +1006,6 @@ public class SmsDispatchersController extends Handler { // Use the legacy architecture. return null; } - - created = true; } if (holder == null) { @@ -965,6 +1029,7 @@ public class SmsDispatchersController extends Handler { * @param holder The {@link DomainSelectionConnectionHolder} that contains the * {@link DomainSelectionConnection} and its related information. */ + @SuppressWarnings("FutureReturnValueIgnored") private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) { DomainSelectionService.SelectionAttributes attr = new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(), @@ -1001,16 +1066,14 @@ public class SmsDispatchersController extends Handler { } /** - * Sends a SMS after selecting the domain via the domain selection service. + * Requests the domain selection for MO SMS. * * @param holder The {@link DomainSelectionConnectionHolder} that contains the * {@link DomainSelectionConnection} and its related information. - * @param request The {@link PendingRequest} that stores the SMS request - * (data, text, multipart text) to be sent. - * @param logTag The log tag to display which method called this method. + * @param logTag The log string. */ - private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, - @NonNull PendingRequest request, @NonNull String logTag) { + private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder, + @NonNull PendingRequest request, String logTag) { boolean isDomainSelectionRequested = holder.isDomainSelectionRequested(); // The domain selection is in progress so waits for the result of // the domain selection by adding this request to the pending list. @@ -1025,6 +1088,120 @@ public class SmsDispatchersController extends Handler { } /** + * Handles an event for sending a SMS after selecting the domain via the domain selection + * service. + * + * @param holder The {@link DomainSelectionConnectionHolder} that contains the + * {@link DomainSelectionConnection} and its related information. + * @param request The {@link PendingRequest} that stores the SMS request + * (data, text, multipart text) to be sent. + * @param logTag The log tag to display which method called this method. + */ + @SuppressWarnings("FutureReturnValueIgnored") + private void handleSendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, + @NonNull PendingRequest request, @NonNull String logTag) { + if (holder.isEmergency()) { + if (mEmergencyStateTracker == null) { + mEmergencyStateTracker = EmergencyStateTracker.getInstance(); + } + + CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencySms(mPhone, + String.valueOf(request.messageId), + isTestEmergencyNumber(request.destAddr)); + future.thenAccept((result) -> { + logi("startEmergencySms(" + logTag + "): messageId=" + request.messageId + + ", result=" + result); + // An emergency SMS should be proceeded regardless of the result of the + // EmergencyStateTracker. + // So the domain selection request should be invoked without checking the result. + requestDomainSelection(holder, request, logTag); + }); + } else { + requestDomainSelection(holder, request, logTag); + } + } + + /** + * Sends a SMS after selecting the domain via the domain selection service. + * + * @param holder The {@link DomainSelectionConnectionHolder} that contains the + * {@link DomainSelectionConnection} and its related information. + * @param request The {@link PendingRequest} that stores the SMS request + * (data, text, multipart text) to be sent. + * @param logTag The log tag to display which method called this method. + */ + private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, + @NonNull PendingRequest request, @NonNull String logTag) { + // Run on main thread for interworking with EmergencyStateTracker + // and adding the pending request. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = holder; + args.arg2 = request; + args.arg3 = logTag; + sendMessage(obtainMessage(EVENT_SEND_SMS_USING_DOMAIN_SELECTION, args)); + } + + /** + * Called when sending MO SMS is complete regardless of the sent result. + * + * @param destAddr The destination address for SMS. + * @param messageId The message id for SMS. + * @param success A flag specifying whether MO SMS is successfully sent or not. + */ + private void handleSmsSentCompletedUsingDomainSelection(@NonNull String destAddr, + long messageId, boolean success) { + if (mEmergencyStateTracker != null) { + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(destAddr)) { + mEmergencyStateTracker.endSms(String.valueOf(messageId), success); + } + } + } + + /** + * Called when MO SMS is successfully sent. + */ + protected void notifySmsSentToEmergencyStateTracker(@NonNull String destAddr, long messageId) { + if (isSmsDomainSelectionEnabled()) { + // Run on main thread for interworking with EmergencyStateTracker. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = destAddr; + args.arg2 = Long.valueOf(messageId); + args.arg3 = Boolean.TRUE; + sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args)); + } + } + + /** + * Called when sending MO SMS is failed. + */ + protected void notifySmsSentFailedToEmergencyStateTracker(@NonNull String destAddr, + long messageId) { + if (isSmsDomainSelectionEnabled()) { + // Run on main thread for interworking with EmergencyStateTracker. + SomeArgs args = SomeArgs.obtain(); + args.arg1 = destAddr; + args.arg2 = Long.valueOf(messageId); + args.arg3 = Boolean.FALSE; + sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args)); + } + } + + private boolean isTestEmergencyNumber(String number) { + try { + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + Map<Integer, List<EmergencyNumber>> eMap = tm.getEmergencyNumberList(); + return eMap.values().stream().flatMap(Collection::stream).anyMatch(eNumber -> + eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST) + && number.equals(eNumber.getNumber())); + } catch (IllegalStateException ise) { + return false; + } catch (RuntimeException r) { + return false; + } + } + + /** * Finishes the domain selection for MO SMS. * * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished. @@ -1054,21 +1231,16 @@ public class SmsDispatchersController extends Handler { } /** - * Notifies the application that MO SMS is not sent by the error of domain selection. + * Called when MO SMS is not sent by the error of domain selection. * * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated. */ - private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) { - final List<PendingRequest> pendingRequests = holder.getPendingRequests(); - - logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size()); - - for (PendingRequest r : pendingRequests) { - triggerSentIntentForFailure(r.sentIntents); - } - + private void handleDomainSelectionTerminatedAbnormally( + @NonNull DomainSelectionConnectionHolder holder) { + logd("handleDomainSelectionTerminatedAbnormally: pendingRequests=" + + holder.getPendingRequests().size()); + sendAllPendingRequests(holder, NetworkRegistrationInfo.DOMAIN_UNKNOWN); holder.setConnection(null); - holder.clearAllRequests(); } /** @@ -1089,12 +1261,36 @@ public class SmsDispatchersController extends Handler { + ", size=" + pendingRequests.size()); } + // When the domain selection request is failed, SMS should be fallback + // to the legacy implementation. + boolean wasDomainUnknown = false; + + if (domain == NetworkRegistrationInfo.DOMAIN_UNKNOWN) { + logd("sendAllPendingRequests: fallback - imsAvailable=" + + mImsSmsDispatcher.isAvailable()); + + wasDomainUnknown = true; + + if (mImsSmsDispatcher.isAvailable()) { + domain = NetworkRegistrationInfo.DOMAIN_PS; + } else { + domain = NetworkRegistrationInfo.DOMAIN_CS; + } + } + for (PendingRequest r : pendingRequests) { switch (r.type) { case PendingRequest.TYPE_DATA: sendData(domain, r); break; case PendingRequest.TYPE_TEXT: + // When the domain selection request is failed, emergency SMS should be fallback + // to the legacy implementation. + if (wasDomainUnknown + && domain != NetworkRegistrationInfo.DOMAIN_PS + && mImsSmsDispatcher.isEmergencySmsSupport(r.destAddr)) { + domain = NetworkRegistrationInfo.DOMAIN_PS; + } sendText(domain, r); break; case PendingRequest.TYPE_MULTIPART_TEXT: @@ -1308,7 +1504,7 @@ public class SmsDispatchersController extends Handler { scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage); } - if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + if (isSmsDomainSelectionEnabled()) { DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); // If the DomainSelectionConnection is not available, @@ -1547,7 +1743,7 @@ public class SmsDispatchersController extends Handler { scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); } - if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + if (isSmsDomainSelectionEnabled()) { TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); boolean isEmergency = tm.isEmergencyNumber(destAddr); DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency); @@ -1696,7 +1892,7 @@ public class SmsDispatchersController extends Handler { scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); } - if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + if (isSmsDomainSelectionEnabled()) { DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); // If the DomainSelectionConnection is not available, diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index f7f24a27ec..74094a320d 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -40,11 +40,14 @@ import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.telephony.flags.FeatureFlagsImpl; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.nitz.NitzStateMachineImpl; +import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccProfile; @@ -286,8 +289,9 @@ public class TelephonyComponentFactory { return new SmsUsageMonitor(context); } - public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) { - return new ServiceStateTracker(phone, ci); + public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci, + @NonNull FeatureFlags featureFlags) { + return new ServiceStateTracker(phone, ci, featureFlags); } /** @@ -326,8 +330,12 @@ public class TelephonyComponentFactory { return new IccPhoneBookInterfaceManager(phone); } - public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone) { - return new IccSmsInterfaceManager(phone); + /** + * Returns a new {@link IccSmsInterfaceManager} instance. + */ + public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone, + @NonNull FeatureFlags featureFlags) { + return new IccSmsInterfaceManager(phone, featureFlags); } /** @@ -377,8 +385,27 @@ public class TelephonyComponentFactory { return new InboundSmsTracker(context, cursor, isCurrentFormat3gpp2); } + /** + * Create an ImsPhoneCallTracker. + * + * @param imsPhone imsphone + * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker + * @deprecated Use {@link #makeImsPhoneCallTracker(ImsPhone, FeatureFlags)} instead + */ public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone) { - return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector); + return makeImsPhoneCallTracker(imsPhone, new FeatureFlagsImpl()); + } + + /** + * Create a ims phone call tracker. + * + * @param imsPhone imsphone + * @param featureFlags feature flags + * @return ImsPhoneCallTracker newly created ImsPhoneCallTracker + */ + public ImsPhoneCallTracker makeImsPhoneCallTracker(ImsPhone imsPhone, + @NonNull FeatureFlags featureFlags) { + return new ImsPhoneCallTracker(imsPhone, ImsManager::getConnector, featureFlags); } public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) { @@ -401,8 +428,12 @@ public class TelephonyComponentFactory { return new AppSmsManager(context); } - public DeviceStateMonitor makeDeviceStateMonitor(Phone phone) { - return new DeviceStateMonitor(phone); + /** + * Create a DeviceStateMonitor. + */ + public DeviceStateMonitor makeDeviceStateMonitor(Phone phone, + @NonNull FeatureFlags featureFlags) { + return new DeviceStateMonitor(phone, featureFlags); } /** @@ -411,9 +442,23 @@ public class TelephonyComponentFactory { * @param phone The phone instance * @param looper Looper for the handler. * @return The access networks manager + * @deprecated {@link #makeAccessNetworksManager(Phone, Looper, FeatureFlags)} instead */ public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper) { - return new AccessNetworksManager(phone, looper); + return new AccessNetworksManager(phone, looper, new FeatureFlagsImpl()); + } + + /** + * Make access networks manager + * + * @param phone The phone instance + * @param looper Looper for the handler. + * @param featureFlags feature flags. + * @return The access networks manager + */ + public AccessNetworksManager makeAccessNetworksManager(Phone phone, Looper looper, + @NonNull FeatureFlags featureFlags) { + return new AccessNetworksManager(phone, looper, featureFlags); } public CdmaSubscriptionSourceManager @@ -429,21 +474,22 @@ public class TelephonyComponentFactory { public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, - TelephonyComponentFactory telephonyComponentFactory) { + TelephonyComponentFactory telephonyComponentFactory, + @NonNull FeatureFlags featureFlags) { return new GsmCdmaPhone(context, ci, notifier, phoneId, precisePhoneType, - telephonyComponentFactory); + telephonyComponentFactory, featureFlags); } public PhoneSwitcher makePhoneSwitcher(int maxDataAttachModemCount, Context context, - Looper looper) { - return PhoneSwitcher.make(maxDataAttachModemCount, context, looper); + Looper looper, @NonNull FeatureFlags featureFlags) { + return PhoneSwitcher.make(maxDataAttachModemCount, context, looper, featureFlags); } /** * Create a new DisplayInfoController. */ - public DisplayInfoController makeDisplayInfoController(Phone phone) { - return new DisplayInfoController(phone); + public DisplayInfoController makeDisplayInfoController(Phone phone, FeatureFlags featureFlags) { + return new DisplayInfoController(phone, featureFlags); } /** @@ -476,10 +522,12 @@ public class TelephonyComponentFactory { * * @param phone The phone object * @param looper The looper for event handling + * @param featureFlags The feature flag. * @return The data network controller instance */ - public DataNetworkController makeDataNetworkController(Phone phone, Looper looper) { - return new DataNetworkController(phone, looper); + public DataNetworkController makeDataNetworkController(Phone phone, Looper looper, + @NonNull FeatureFlags featureFlags) { + return new DataNetworkController(phone, looper, featureFlags); } /** @@ -490,15 +538,17 @@ public class TelephonyComponentFactory { * @param dataServiceManager Data service manager instance. * @param looper The looper to be used by the handler. Currently the handler thread is the phone * process's main thread. + * @param featureFlags Feature flags controlling which feature is enabled. * * @param callback Callback for passing events back to data network controller. * @return The data profile manager instance. */ public @NonNull DataProfileManager makeDataProfileManager(@NonNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags, @NonNull DataProfileManager.DataProfileManagerCallback callback) { return new DataProfileManager(phone, dataNetworkController, dataServiceManager, looper, - callback); + featureFlags, callback); } /** @@ -516,4 +566,9 @@ public class TelephonyComponentFactory { @NonNull DataSettingsManager.DataSettingsManagerCallback callback) { return new DataSettingsManager(phone, dataNetworkController, looper, callback); } + + /** Create CellularIdentifierDisclosureNotifier. */ + public CellularIdentifierDisclosureNotifier makeIdentifierDisclosureNotifier() { + return CellularIdentifierDisclosureNotifier.getInstance(); + } } diff --git a/src/java/com/android/internal/telephony/analytics/CallAnalyticsProvider.java b/src/java/com/android/internal/telephony/analytics/CallAnalyticsProvider.java new file mode 100644 index 0000000000..e0da0f19a5 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/CallAnalyticsProvider.java @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.CallAnalyticsTable; +import com.android.telephony.Rlog; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; + +/** + * Provider class for calls, receives the data from CallAnalytics and performs business logic on the + * received data. It uses util class for required db operation. This class implements the + * TelephonyAnalyticsProvider interface to provide aggregation functionality. + */ +public class CallAnalyticsProvider implements TelephonyAnalyticsProvider { + private static final String TAG = CallAnalyticsProvider.class.getSimpleName(); + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00"); + private TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + private String mDateOfDeletedRecordsCallTable; + private static final String CREATE_CALL_ANALYTICS_TABLE = + "CREATE TABLE IF NOT EXISTS " + + CallAnalyticsTable.TABLE_NAME + + "(" + + CallAnalyticsTable._ID + + " INTEGER PRIMARY KEY," + + CallAnalyticsTable.LOG_DATE + + " DATE ," + + CallAnalyticsTable.CALL_STATUS + + " TEXT DEFAULT ''," + + CallAnalyticsTable.CALL_TYPE + + " TEXT DEFAULT ''," + + CallAnalyticsTable.RAT + + " TEXT DEFAULT ''," + + CallAnalyticsTable.SLOT_ID + + " INTEGER ," + + CallAnalyticsTable.FAILURE_REASON + + " TEXT DEFAULT ''," + + CallAnalyticsTable.RELEASE_VERSION + + " TEXT DEFAULT '' , " + + CallAnalyticsTable.COUNT + + " INTEGER DEFAULT 1 " + + ");"; + + private static final String[] CALL_INSERTION_PROJECTION = { + CallAnalyticsTable._ID, CallAnalyticsTable.COUNT + }; + + private static final String CALL_SUCCESS_INSERTION_SELECTION = + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.LOG_DATE + + " = ? AND " + + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? "; + + private static final String CALL_FAILED_INSERTION_SELECTION = + CallAnalyticsTable.LOG_DATE + + " = ? AND " + + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? AND " + + CallAnalyticsTable.RAT + + " = ? AND " + + CallAnalyticsTable.FAILURE_REASON + + " = ? AND " + + CallAnalyticsTable.RELEASE_VERSION + + " = ? "; + + private static final String CALL_OLD_DATA_DELETION_SELECTION = + CallAnalyticsTable.LOG_DATE + " < ? "; + + private static final String CALL_OVERFLOW_DATA_DELETION_SELECTION = + CallAnalyticsTable._ID + + " IN " + + " ( SELECT " + + CallAnalyticsTable._ID + + " FROM " + + CallAnalyticsTable.TABLE_NAME + + " ORDER BY " + + CallAnalyticsTable.LOG_DATE + + " DESC LIMIT -1 OFFSET ? )"; + + private enum CallStatus { + SUCCESS("Success"), + FAILURE("Failure"); + public String value; + + CallStatus(String value) { + this.value = value; + } + } + + private enum CallType { + NORMAL("Normal Call"), + SOS("SOS Call"); + public String value; + + CallType(String value) { + this.value = value; + } + } + + private final int mSlotIndex; + + /** + * Initializes the CallAnalyticsProvider object and creates a table in the DB to log the + * information related to Calls. + * + * @param telephonyAnalyticsUtil : Util Class object to support db operations + * @param slotIndex : Logical slot index. + */ + public CallAnalyticsProvider(TelephonyAnalyticsUtil telephonyAnalyticsUtil, int slotIndex) { + mTelephonyAnalyticsUtil = telephonyAnalyticsUtil; + mSlotIndex = slotIndex; + mTelephonyAnalyticsUtil.createTable(CREATE_CALL_ANALYTICS_TABLE); + } + + private ContentValues getContentValues( + String callType, String callStatus, int slotId, String rat, String failureReason) { + ContentValues values = new ContentValues(); + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(CallAnalyticsTable.LOG_DATE, dateToday); + values.put(CallAnalyticsTable.CALL_TYPE, callType); + values.put(CallAnalyticsTable.CALL_STATUS, callStatus); + values.put(CallAnalyticsTable.SLOT_ID, slotId); + values.put(CallAnalyticsTable.RAT, rat); + values.put(CallAnalyticsTable.FAILURE_REASON, failureReason); + values.put(CallAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + return values; + } + + private String[] getSuccessfulCallSelectionArgs(ContentValues values) { + return new String[] { + values.getAsString(CallAnalyticsTable.CALL_TYPE), + values.getAsString(CallAnalyticsTable.LOG_DATE), + CallStatus.SUCCESS.value, + values.getAsString(CallAnalyticsTable.SLOT_ID) + }; + } + + private String[] getFailedCallSelectionArgs(ContentValues values) { + + return new String[] { + values.getAsString(CallAnalyticsTable.LOG_DATE), + values.getAsString(CallAnalyticsTable.CALL_STATUS), + values.getAsString(CallAnalyticsTable.CALL_TYPE), + values.getAsString(CallAnalyticsTable.SLOT_ID), + values.getAsString(CallAnalyticsTable.RAT), + values.getAsString(CallAnalyticsTable.FAILURE_REASON), + values.getAsString(CallAnalyticsTable.RELEASE_VERSION) + }; + } + + /** + * Receives data, processes it and sends for insertion to db. + * + * @param callType : Type of the Call , i.e. Normal or Sos + * @param callStatus : Defines call was success or failure + * @param slotId : Logical Slot index derived from Phone object. + * @param rat : Radio Access Technology on which call ended. + * @param failureReason : Failure Reason of the call. + */ + public void insertDataToDb( + String callType, String callStatus, int slotId, String rat, String failureReason) { + ContentValues values = getContentValues(callType, callStatus, slotId, rat, failureReason); + Cursor cursor = null; + try { + if (values.getAsString(CallAnalyticsTable.CALL_STATUS) + .equals(CallStatus.SUCCESS.value)) { + Rlog.d(TAG, "Insertion for Success Call"); + String[] selectionArgs = getSuccessfulCallSelectionArgs(values); + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + CALL_INSERTION_PROJECTION, + CALL_SUCCESS_INSERTION_SELECTION, + selectionArgs, + null, + null, + null, + null); + } else { + + String[] selectionArgs = getFailedCallSelectionArgs(values); + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + CALL_INSERTION_PROJECTION, + CALL_FAILED_INSERTION_SELECTION, + selectionArgs, + null, + null, + null, + null); + } + updateEntryIfExistsOrInsert(cursor, values); + deleteOldAndOverflowData(); + } catch (Exception e) { + Rlog.e(TAG, "Error caught in insertDataToDb while insertion."); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + private void updateEntryIfExistsOrInsert(Cursor cursor, ContentValues values) { + if (cursor != null && cursor.moveToFirst()) { + int idColumnIndex = cursor.getColumnIndex(CallAnalyticsTable._ID); + int countColumnIndex = cursor.getColumnIndex(CallAnalyticsTable.COUNT); + if (idColumnIndex != -1 && countColumnIndex != -1) { + int id = cursor.getInt(idColumnIndex); + int count = cursor.getInt(countColumnIndex); + int newCount = count + 1; + + values.put(CallAnalyticsTable.COUNT, newCount); + + String updateSelection = CallAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {String.valueOf(id)}; + Rlog.d(TAG, "Updated Count = " + values.getAsString(CallAnalyticsTable.COUNT)); + + mTelephonyAnalyticsUtil.update( + CallAnalyticsTable.TABLE_NAME, + values, + updateSelection, + updateSelectionArgs); + } + } else { + Rlog.d(TAG, "Simple Insertion"); + mTelephonyAnalyticsUtil.insert(CallAnalyticsTable.TABLE_NAME, values); + } + } + + /** Gets the count stored in the cursor object. */ + @VisibleForTesting + public long getCount( + String tableName, + String[] columns, + String selection, + String[] selectionArgs, + String groupBy, + String having, + String orderBy, + String limit) { + Cursor cursor = null; + long totalCount = 0; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + having, + orderBy, + limit); + totalCount = mTelephonyAnalyticsUtil.getCountFromCursor(cursor); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return totalCount; + } + + private String[] getColumnSelectionAndArgs(String callType, String callStatus) { + String selection; + String[] selectionAndArgs; + if (callType != null) { + if (callStatus != null) { + selection = + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? "; + selectionAndArgs = + new String[] { + selection, callType, callStatus, Integer.toString(mSlotIndex) + }; + } else { + selection = + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? "; + selectionAndArgs = new String[] {selection, callType, Integer.toString(mSlotIndex)}; + } + } else { + if (callStatus != null) { + selection = + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? "; + selectionAndArgs = + new String[] {selection, callStatus, Integer.toString(mSlotIndex)}; + } else { + selection = CallAnalyticsTable.SLOT_ID + " = ? "; + selectionAndArgs = new String[] {selection, Integer.toString(mSlotIndex)}; + } + } + return selectionAndArgs; + } + + private long countCallsOfTypeAndStatus(String callType, String callStatus) { + int selectionIndex = 0; + String[] columns = {"sum(" + CallAnalyticsTable.COUNT + ")"}; + String[] selectionAndArgs = getColumnSelectionAndArgs(callType, callStatus); + String selection = selectionAndArgs[selectionIndex]; + int selectionArgsStartIndex = 1, selectionArgsEndIndex = selectionAndArgs.length; + String[] selectionArgs = + Arrays.copyOfRange( + selectionAndArgs, selectionArgsStartIndex, selectionArgsEndIndex); + return getCount( + CallAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + null, + null, + null, + null); + } + + private long countTotalCalls() { + return countCallsOfTypeAndStatus(null, null); + } + + private long countFailedCalls() { + return countCallsOfTypeAndStatus(null, CallStatus.FAILURE.value); + } + + private long countNormalCalls() { + return countCallsOfTypeAndStatus(CallType.NORMAL.value, null); + } + + private long countFailedNormalCalls() { + return countCallsOfTypeAndStatus(CallType.NORMAL.value, CallStatus.FAILURE.value); + } + + private long countSosCalls() { + return countCallsOfTypeAndStatus(CallType.SOS.value, null); + } + + private long countFailedSosCalls() { + return countCallsOfTypeAndStatus(CallType.SOS.value, CallStatus.FAILURE.value); + } + + private String getMaxFailureVersion() { + String[] columns = {CallAnalyticsTable.RELEASE_VERSION}; + String selection = + CallAnalyticsTable.CALL_STATUS + " = ? AND " + CallAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {CallStatus.FAILURE.value, Integer.toString(mSlotIndex)}; + String groupBy = CallAnalyticsTable.RELEASE_VERSION; + String orderBy = "SUM(" + CallAnalyticsTable.COUNT + ") DESC "; + String limit = "1"; + Cursor cursor = null; + String version = ""; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + orderBy, + limit); + + if (cursor != null && cursor.moveToFirst()) { + int releaseVersionColumnIndex = + cursor.getColumnIndex(CallAnalyticsTable.RELEASE_VERSION); + if (releaseVersionColumnIndex != -1) { + version = cursor.getString(releaseVersionColumnIndex); + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return version; + } + + private String getMaxFailureNetworkType() { + String[] columns = {CallAnalyticsTable.RAT}; + String selection = + CallAnalyticsTable.CALL_STATUS + " = ? AND " + CallAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {CallStatus.FAILURE.value, Integer.toString(mSlotIndex)}; + String groupBy = CallAnalyticsTable.RAT; + String orderBy = "SUM(" + CallAnalyticsTable.COUNT + ") DESC "; + String limit = "1"; + Cursor cursor = null; + String networkType = ""; + + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + orderBy, + limit); + + if (cursor != null && cursor.moveToFirst()) { + int networkColumnIndex = cursor.getColumnIndex(CallAnalyticsTable.RAT); + networkType = cursor.getString(networkColumnIndex); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return networkType; + } + + private HashMap<String, Integer> getFailureCountByRatForCallType(String callType) { + return getFailureCountByColumnForCallType(CallAnalyticsTable.RAT, callType); + } + + private HashMap<String, Integer> getFailureCountByReasonForCallType(String callType) { + return getFailureCountByColumnForCallType(CallAnalyticsTable.FAILURE_REASON, callType); + } + + private HashMap<String, Integer> getFailureCountByColumnForCallType( + String column, String callType) { + String[] columns = {column, "SUM(" + CallAnalyticsTable.COUNT + ") AS count"}; + String selection = + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {callType, CallStatus.FAILURE.value, Integer.toString(mSlotIndex)}; + String groupBy = column; + Cursor cursor = null; + HashMap<String, Integer> failureCountByReason = new HashMap<>(); + + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + CallAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + null, + null); + + if (cursor != null) { + int failureColumnIndex = cursor.getColumnIndex(column); + int failureCountColumnIndex = cursor.getColumnIndex("count"); + + if (failureCountColumnIndex != -1 && failureColumnIndex != -1) { + while (cursor.moveToNext()) { + String failureReason = cursor.getString(failureColumnIndex); + int failureCount = cursor.getInt(failureCountColumnIndex); + failureCountByReason.put(failureReason, failureCount); + } + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return failureCountByReason; + } + + protected void deleteOldAndOverflowData() { + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + if (mDateOfDeletedRecordsCallTable == null + || !mDateOfDeletedRecordsCallTable.equals(dateToday)) { + mTelephonyAnalyticsUtil.deleteOverflowAndOldData( + CallAnalyticsTable.TABLE_NAME, + CALL_OVERFLOW_DATA_DELETION_SELECTION, + CALL_OLD_DATA_DELETION_SELECTION); + mDateOfDeletedRecordsCallTable = dateToday; + } + } + + /** Setter function for mDateOfDeletedRecordsCallTable. */ + public void setDateOfDeletedRecordsCallTable(String dateOfDeletedRecordsCallTable) { + mDateOfDeletedRecordsCallTable = dateOfDeletedRecordsCallTable; + } + + private ArrayList<String> dumpInformationInList( + long totalCalls, + long failedCalls, + double percentageFailedCalls, + long normalCallsCount, + double percentageFailedNormalCalls, + long sosCallCount, + double percentageFailedSosCalls, + String maxFailureVersion, + String maxFailureNetworkType, + HashMap<String, Integer> failureCountByReasonNormalCall, + HashMap<String, Integer> failureCountByReasonSosCall, + HashMap<String, Integer> failureCountByRatNormalCall, + HashMap<String, Integer> failureCountByRatSosCall) { + + ArrayList<String> aggregatedCallInformation = new ArrayList<>(); + aggregatedCallInformation.add("Normal Call Stats"); + aggregatedCallInformation.add("\tTotal Normal Calls = " + normalCallsCount); + aggregatedCallInformation.add( + "\tPercentage Failure of Normal Calls = " + + DECIMAL_FORMAT.format(percentageFailedNormalCalls) + + "%"); + addFailureStatsFromHashMap( + failureCountByReasonNormalCall, + CallType.NORMAL.value, + normalCallsCount, + CallAnalyticsTable.FAILURE_REASON, + aggregatedCallInformation); + addFailureStatsFromHashMap( + failureCountByRatNormalCall, + CallType.NORMAL.value, + normalCallsCount, + CallAnalyticsTable.RAT, + aggregatedCallInformation); + + if (sosCallCount > 0) { + aggregatedCallInformation.add("SOS Call Stats"); + aggregatedCallInformation.add("\tTotal SOS Calls = " + sosCallCount); + aggregatedCallInformation.add( + "\tPercentage Failure of SOS Calls = " + + DECIMAL_FORMAT.format(percentageFailedSosCalls) + + "%"); + addFailureStatsFromHashMap( + failureCountByReasonSosCall, + CallType.SOS.value, + sosCallCount, + CallAnalyticsTable.FAILURE_REASON, + aggregatedCallInformation); + addFailureStatsFromHashMap( + failureCountByRatSosCall, + CallType.SOS.value, + sosCallCount, + CallAnalyticsTable.RAT, + aggregatedCallInformation); + } + if (failedCalls != 0) { + aggregatedCallInformation.add( + "\tMax Call(Normal+SOS) Failures at Version : " + maxFailureVersion); + aggregatedCallInformation.add( + "\tMax Call(Normal+SOS) Failures at Network Type: " + maxFailureNetworkType); + } + + return aggregatedCallInformation; + } + + private void addFailureStatsFromHashMap( + HashMap<String, Integer> failureCountByColumn, + String callType, + long totalCallsOfCallType, + String column, + ArrayList<String> aggregatedCallInformation) { + failureCountByColumn.forEach( + (k, v) -> { + double percentageFail = (double) v / (double) totalCallsOfCallType * 100.0; + aggregatedCallInformation.add( + "\tNo. of " + + callType + + " failures at " + + column + + " : " + + k + + " = " + + v + + ", Percentage = " + + DECIMAL_FORMAT.format(percentageFail) + + "%"); + }); + } + + /** + * Collects all information which is intended to be a part of the report by calling the required + * functions implemented in the class. + * + * @return List which contains all the Calls related information + */ + public ArrayList<String> aggregate() { + long totalCalls = countTotalCalls(); + long failedCalls = countFailedCalls(); + double percentageFailedCalls = (double) failedCalls / (double) totalCalls * 100.0; + String maxFailuresVersion = getMaxFailureVersion(); + String maxFailuresNetworkType = getMaxFailureNetworkType(); + HashMap<String, Integer> failureCountByReasonNormalCall = + getFailureCountByReasonForCallType(CallType.NORMAL.value); + HashMap<String, Integer> failureCountByReasonSosCall = + getFailureCountByReasonForCallType(CallType.SOS.value); + HashMap<String, Integer> failureCountByRatNormalCall = + getFailureCountByRatForCallType(CallType.NORMAL.value); + HashMap<String, Integer> failureCountByRatSosCall = + getFailureCountByRatForCallType(CallType.SOS.value); + long normalCallsCount = countNormalCalls(); + long normalCallFailureCount = countFailedNormalCalls(); + double percentageFailureNormalCall = + (double) normalCallFailureCount / (double) normalCallsCount * 100.0; + long sosCallCount = countSosCalls(); + long sosCallFailureCount = countFailedSosCalls(); + double percentageFailureSosCall = + (double) sosCallFailureCount / (double) sosCallCount * 100.0; + ArrayList<String> aggregatedCallInformation = + dumpInformationInList( + totalCalls, + failedCalls, + percentageFailedCalls, + normalCallsCount, + percentageFailureNormalCall, + sosCallCount, + percentageFailureSosCall, + maxFailuresVersion, + maxFailuresNetworkType, + failureCountByReasonNormalCall, + failureCountByReasonSosCall, + failureCountByRatNormalCall, + failureCountByRatSosCall); + return aggregatedCallInformation; + } +} diff --git a/src/java/com/android/internal/telephony/analytics/ServiceStateAnalyticsProvider.java b/src/java/com/android/internal/telephony/analytics/ServiceStateAnalyticsProvider.java new file mode 100644 index 0000000000..cae44bdc81 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/ServiceStateAnalyticsProvider.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.analytics.TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState; +import com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.ServiceStateAnalyticsTable; +import com.android.telephony.Rlog; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; + +/** + * Provider class for ServiceState. Receives the data from ServiceStateAnalytics. Performs business + * logic on the received data. Uses Util class for required db operation. Implements the + * TelephonyAnalyticsProvider interface to provide aggregation functionality. + */ +public class ServiceStateAnalyticsProvider implements TelephonyAnalyticsProvider { + protected TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + private static final String TAG = ServiceStateAnalyticsProvider.class.getSimpleName(); + private static final String CREATE_SERVICE_STATE_TABLE_QUERY = + "CREATE TABLE IF NOT EXISTS " + + ServiceStateAnalyticsTable.TABLE_NAME + + " ( " + + ServiceStateAnalyticsTable._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ServiceStateAnalyticsTable.LOG_DATE + + " DATE ," + + ServiceStateAnalyticsTable.SLOT_ID + + " INTEGER , " + + ServiceStateAnalyticsTable.TIME_DURATION + + " INTEGER ," + + ServiceStateAnalyticsTable.RAT + + " TEXT ," + + ServiceStateAnalyticsTable.DEVICE_STATUS + + " TEXT ," + + ServiceStateAnalyticsTable.RELEASE_VERSION + + " TEXT " + + ");"; + + private static final String[] SERVICE_STATE_INSERTION_COLUMNS = { + ServiceStateAnalyticsTable._ID, ServiceStateAnalyticsTable.TIME_DURATION + }; + + private String mDateOfDeletedRecordsServiceStateTable; + + private static final String SERVICE_STATE_INSERTION_SELECTION = + ServiceStateAnalyticsTable.LOG_DATE + + " = ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? AND " + + ServiceStateAnalyticsTable.RAT + + " = ? AND " + + ServiceStateAnalyticsTable.DEVICE_STATUS + + " = ? AND " + + ServiceStateAnalyticsTable.RELEASE_VERSION + + " = ? "; + + private static final String SERVICE_STATE_OVERFLOW_DATA_DELETION_SELECTION = + ServiceStateAnalyticsTable._ID + + " IN " + + " ( SELECT " + + ServiceStateAnalyticsTable._ID + + " FROM " + + ServiceStateAnalyticsTable.TABLE_NAME + + " ORDER BY " + + ServiceStateAnalyticsTable.LOG_DATE + + " DESC LIMIT -1 OFFSET ? )"; + + private static final String SERVICE_STATE_OLD_DATA_DELETION_SELECTION = + ServiceStateAnalyticsTable.LOG_DATE + " < ? "; + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00"); + + private final int mSlotIndex; + + /** + * Instantiates the ServiceStateAnalyticsProvider Object. Creates a table in the db for Storing + * ServiceState Related Information. + */ + public ServiceStateAnalyticsProvider(TelephonyAnalyticsUtil databaseUtil, int slotIndex) { + mTelephonyAnalyticsUtil = databaseUtil; + mSlotIndex = slotIndex; + mTelephonyAnalyticsUtil.createTable(CREATE_SERVICE_STATE_TABLE_QUERY); + } + + private ContentValues getContentValues( + TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState lastState, + long endTimeStamp) { + ContentValues values = new ContentValues(); + long timeInterval = endTimeStamp - lastState.mTimestampStart; + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(ServiceStateAnalyticsTable.LOG_DATE, dateToday); + values.put(ServiceStateAnalyticsTable.TIME_DURATION, timeInterval); + values.put(ServiceStateAnalyticsTable.SLOT_ID, lastState.mSlotIndex); + values.put(ServiceStateAnalyticsTable.RAT, lastState.mRAT); + values.put(ServiceStateAnalyticsTable.DEVICE_STATUS, lastState.mDeviceStatus); + values.put(ServiceStateAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + + return values; + } + + /** Receives the data, processes it and sends it for insertion to db. */ + @VisibleForTesting + public void insertDataToDb(TimeStampedServiceState lastState, long endTimeStamp) { + ContentValues values = getContentValues(lastState, endTimeStamp); + Rlog.d(TAG, " " + values.toString() + "Time = " + System.currentTimeMillis()); + String[] selectionArgs = { + values.getAsString(ServiceStateAnalyticsTable.LOG_DATE), + values.getAsString(ServiceStateAnalyticsTable.SLOT_ID), + values.getAsString(ServiceStateAnalyticsTable.RAT), + values.getAsString(ServiceStateAnalyticsTable.DEVICE_STATUS), + values.getAsString(ServiceStateAnalyticsTable.RELEASE_VERSION) + }; + Cursor cursor = null; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + ServiceStateAnalyticsTable.TABLE_NAME, + SERVICE_STATE_INSERTION_COLUMNS, + SERVICE_STATE_INSERTION_SELECTION, + selectionArgs, + null, + null, + null, + null); + updateIfEntryExistsOtherwiseInsert(cursor, values); + deleteOldAndOverflowData(); + + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + private void updateIfEntryExistsOtherwiseInsert(Cursor cursor, ContentValues values) { + if (cursor != null && cursor.moveToFirst()) { + int idIndex = cursor.getColumnIndex(ServiceStateAnalyticsTable._ID); + int timeDurationIndex = cursor.getColumnIndex(ServiceStateAnalyticsTable.TIME_DURATION); + if (idIndex != -1 && timeDurationIndex != -1) { + int id = cursor.getInt(idIndex); + int oldTimeDuration = cursor.getInt(timeDurationIndex); + int updatedTimeDuration = + oldTimeDuration + + Integer.parseInt( + values.getAsString( + ServiceStateAnalyticsTable.TIME_DURATION)); + String updateSelection = ServiceStateAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {Integer.toString(id)}; + values.put(ServiceStateAnalyticsTable.TIME_DURATION, updatedTimeDuration); + mTelephonyAnalyticsUtil.update( + ServiceStateAnalyticsTable.TABLE_NAME, + values, + updateSelection, + updateSelectionArgs); + } + } else { + mTelephonyAnalyticsUtil.insert(ServiceStateAnalyticsTable.TABLE_NAME, values); + } + } + + private long getTotalUpTime() { + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = ServiceStateAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + Cursor cursor = null; + long duration = 0; + + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + ServiceStateAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + null, + null, + null, + null); + if (cursor != null && cursor.moveToFirst()) { + duration = cursor.getLong(0); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return duration; + } + + private long outOfServiceDuration() { + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? " + + " AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + long oosDuration = 0; + Cursor cursor = null; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + ServiceStateAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + null, + null, + null, + null); + if (cursor != null && cursor.moveToFirst()) { + oosDuration = cursor.getLong(0); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return oosDuration; + } + + private HashMap<String, Long> getOutOfServiceDurationByReason() { + HashMap<String, Long> outOfServiceDurationByReason = new HashMap<>(); + String[] columns = { + ServiceStateAnalyticsTable.DEVICE_STATUS, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.DEVICE_STATUS; + Cursor cursor = null; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + ServiceStateAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + null, + null); + + if (cursor != null) { + int reasonIndex = cursor.getColumnIndex(ServiceStateAnalyticsTable.DEVICE_STATUS); + int timeIndex = cursor.getColumnIndex("totalTime"); + + if (reasonIndex != -1 && timeIndex != -1) { + while (cursor.moveToNext()) { + String oosReason = cursor.getString(reasonIndex); + long timeInterval = cursor.getLong(timeIndex); + outOfServiceDurationByReason.put(oosReason, timeInterval); + } + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return outOfServiceDurationByReason; + } + + private HashMap<String, Long> getInServiceDurationByRat() { + HashMap<String, Long> inServiceDurationByRat = new HashMap<>(); + String[] columns = { + ServiceStateAnalyticsTable.RAT, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.RAT + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"NA", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.RAT; + Cursor cursor = null; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + ServiceStateAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + null, + null); + + if (cursor != null) { + int ratIndex = cursor.getColumnIndex(ServiceStateAnalyticsTable.RAT); + int timeIndex = cursor.getColumnIndex("totalTime"); + + if (ratIndex != -1 && timeIndex != -1) { + while (cursor.moveToNext()) { + String rat = cursor.getString(ratIndex); + long timeInterval = cursor.getLong(timeIndex); + inServiceDurationByRat.put(rat, timeInterval); + } + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return inServiceDurationByRat; + } + + protected void deleteOldAndOverflowData() { + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + if (mDateOfDeletedRecordsServiceStateTable == null + || !mDateOfDeletedRecordsServiceStateTable.equals(dateToday)) { + mTelephonyAnalyticsUtil.deleteOverflowAndOldData( + ServiceStateAnalyticsTable.TABLE_NAME, + SERVICE_STATE_OVERFLOW_DATA_DELETION_SELECTION, + SERVICE_STATE_OLD_DATA_DELETION_SELECTION); + mDateOfDeletedRecordsServiceStateTable = dateToday; + } + } + + /** Setter function for mDateOfDeletedRecordsServiceStateTable */ + public void setDateOfDeletedRecordsServiceStateTable( + String dateOfDeletedRecordsServiceStateTable) { + mDateOfDeletedRecordsServiceStateTable = dateOfDeletedRecordsServiceStateTable; + } + + private ArrayList<String> dumpInformationInList( + Long upTime, + Long outOfServiceTime, + double percentageOutOfService, + HashMap<String, Long> oosByReason, + HashMap<String, Long> timeDurationByRat) { + ArrayList<String> aggregatedServiceStateInfo = new ArrayList<>(); + aggregatedServiceStateInfo.add("Total UpTime = " + upTime + " millis"); + aggregatedServiceStateInfo.add( + "Out of Service Time = " + + outOfServiceTime + + " millis, Percentage " + + DECIMAL_FORMAT.format(percentageOutOfService) + + "%"); + oosByReason.forEach( + (k, v) -> { + double percentageOosOfReason; + if (upTime == 0) { + percentageOosOfReason = 0.0; + } else { + percentageOosOfReason = (double) v / (double) upTime * 100.0; + } + aggregatedServiceStateInfo.add( + "Out of service Reason = " + + k + + ", Percentage = " + + DECIMAL_FORMAT.format(percentageOosOfReason) + + "%"); + }); + timeDurationByRat.forEach( + (k, v) -> { + double percentageInService; + if (upTime == 0) { + percentageInService = 0.0; + } else { + percentageInService = (double) v / (double) upTime * 100.0; + } + aggregatedServiceStateInfo.add( + "IN_SERVICE RAT : " + + k + + ", Percentage = " + + DECIMAL_FORMAT.format(percentageInService) + + "%"); + }); + return aggregatedServiceStateInfo; + } + + /** + * Collects all information which is intended to be a part of the report by calling the required + * functions implemented in the class. + * + * @return List which contains all the ServiceState related collected information. + */ + public ArrayList<String> aggregate() { + + long upTime = getTotalUpTime(); + long outOfServiceTime = outOfServiceDuration(); + double percentageOutOfService; + if (upTime == 0) { + percentageOutOfService = 0.0; + } else { + percentageOutOfService = (double) outOfServiceTime / upTime * 100.0; + } + HashMap<String, Long> oosByReason = getOutOfServiceDurationByReason(); + HashMap<String, Long> timeDurationByRat = getInServiceDurationByRat(); + return dumpInformationInList( + upTime, outOfServiceTime, percentageOutOfService, oosByReason, timeDurationByRat); + } +} diff --git a/src/java/com/android/internal/telephony/analytics/SmsMmsAnalyticsProvider.java b/src/java/com/android/internal/telephony/analytics/SmsMmsAnalyticsProvider.java new file mode 100644 index 0000000000..e544765756 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/SmsMmsAnalyticsProvider.java @@ -0,0 +1,526 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable; +import com.android.telephony.Rlog; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; + +/** + * Provider class for Sms and Mms Receives the data from SmsMmsAnalytics Performs business logic on + * the received data Uses Util class for required db operation. Implements the + * TelephonyAnalyticsProvider interface to provide aggregation functionality. + */ +public class SmsMmsAnalyticsProvider implements TelephonyAnalyticsProvider { + private static final String TAG = SmsMmsAnalyticsProvider.class.getSimpleName(); + + private TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + private String mDateOfDeletedRecordsSmsMmsTable; + + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.00"); + private static final String CREATE_SMS_MMS_ANALYTICS_TABLE = + "CREATE TABLE IF NOT EXISTS " + + SmsMmsAnalyticsTable.TABLE_NAME + + "(" + + SmsMmsAnalyticsTable._ID + + " INTEGER PRIMARY KEY," + + SmsMmsAnalyticsTable.LOG_DATE + + " DATE ," + + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " TEXT DEFAULT ''," + + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " TEXT DEFAULT ''," + + SmsMmsAnalyticsTable.SLOT_ID + + " INTEGER , " + + SmsMmsAnalyticsTable.RAT + + " TEXT DEFAULT ''," + + SmsMmsAnalyticsTable.FAILURE_REASON + + " TEXT DEFAULT ''," + + SmsMmsAnalyticsTable.RELEASE_VERSION + + " TEXT DEFAULT '' , " + + SmsMmsAnalyticsTable.COUNT + + " INTEGER DEFAULT 1 " + + ");"; + private static final String SMS_MMS_OVERFLOW_DATA_DELETION_SELECTION = + SmsMmsAnalyticsTable._ID + + " IN " + + " ( SELECT " + + SmsMmsAnalyticsTable._ID + + " FROM " + + SmsMmsAnalyticsTable.TABLE_NAME + + " ORDER BY " + + SmsMmsAnalyticsTable.LOG_DATE + + " DESC LIMIT -1 OFFSET ? ) "; + private static final String SMS_MMS_OLD_DATA_DELETION_SELECTION = + SmsMmsAnalyticsTable.LOG_DATE + " < ? "; + + private enum SmsMmsType { + SMS_OUTGOING("SMS Outgoing"), + SMS_INCOMING("SMS Incoming"), + MMS_OUTGOING("MMS Outgoing"), + MMS_INCOMING("MMS Incoming"); + public final String value; + + SmsMmsType(String value) { + this.value = value; + } + } + + private enum SmsMmsStatus { + SUCCESS("Success"), + FAILURE("Failure"); + public final String value; + + SmsMmsStatus(String value) { + this.value = value; + } + } + + private final int mSlotIndex; + + public SmsMmsAnalyticsProvider(TelephonyAnalyticsUtil databaseUtil, int slotIndex) { + mTelephonyAnalyticsUtil = databaseUtil; + mSlotIndex = slotIndex; + mTelephonyAnalyticsUtil.createTable(CREATE_SMS_MMS_ANALYTICS_TABLE); + } + + private static final String[] SMS_MMS_INSERTION_PROJECTION = { + SmsMmsAnalyticsTable._ID, SmsMmsAnalyticsTable.COUNT + }; + + private static final String SMS_MMS_INSERTION_SUCCESS_SELECTION = + SmsMmsAnalyticsTable.LOG_DATE + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + SmsMmsAnalyticsTable.SLOT_ID + + " = ? "; + + private static final String SMS_MMS_INSERTION_FAILURE_SELECTION = + SmsMmsAnalyticsTable.LOG_DATE + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + SmsMmsAnalyticsTable.RAT + + " = ? AND " + + SmsMmsAnalyticsTable.SLOT_ID + + " = ? AND " + + SmsMmsAnalyticsTable.FAILURE_REASON + + " = ? AND " + + SmsMmsAnalyticsTable.RELEASE_VERSION + + " = ? "; + + private ContentValues getContentValues( + String status, String smsMmsType, String rat, String failureReason) { + ContentValues values = new ContentValues(); + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(SmsMmsAnalyticsTable.LOG_DATE, dateToday); + values.put(SmsMmsAnalyticsTable.SMS_MMS_STATUS, status); + values.put(SmsMmsAnalyticsTable.SMS_MMS_TYPE, smsMmsType); + values.put(SmsMmsAnalyticsTable.RAT, rat); + values.put(SmsMmsAnalyticsTable.SLOT_ID, mSlotIndex); + values.put(SmsMmsAnalyticsTable.FAILURE_REASON, failureReason); + values.put(SmsMmsAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + return values; + } + + /** + * Processes the received data for insertion to the database. + * + * @param status : SMS Status ,i.e. Success or Failure + * @param smsMmsType : Type ,i.e. outgoing/incoming + * @param rat : Radio Access Technology + * @param failureReason : Reason for failure + */ + @VisibleForTesting + public void insertDataToDb(String status, String smsMmsType, String rat, String failureReason) { + ContentValues values = getContentValues(status, smsMmsType, rat, failureReason); + Rlog.d(TAG, values.toString()); + Cursor cursor = null; + String[] selectionArgs; + try { + if (values.getAsString(SmsMmsAnalyticsTable.SMS_MMS_STATUS) + .equals(SmsMmsStatus.SUCCESS.value)) { + Rlog.d(TAG, "Success Entry Data for Sms/Mms: " + values.toString()); + selectionArgs = + new String[] { + values.getAsString(SmsMmsAnalyticsTable.LOG_DATE), + values.getAsString(SmsMmsAnalyticsTable.SMS_MMS_TYPE), + values.getAsString(SmsMmsAnalyticsTable.SMS_MMS_STATUS), + values.getAsString(SmsMmsAnalyticsTable.SLOT_ID) + }; + cursor = + mTelephonyAnalyticsUtil.getCursor( + SmsMmsAnalyticsTable.TABLE_NAME, + SMS_MMS_INSERTION_PROJECTION, + SMS_MMS_INSERTION_SUCCESS_SELECTION, + selectionArgs, + null, + null, + null, + null); + + } else { + selectionArgs = + new String[] { + values.getAsString(SmsMmsAnalyticsTable.LOG_DATE), + values.getAsString(SmsMmsAnalyticsTable.SMS_MMS_STATUS), + values.getAsString(SmsMmsAnalyticsTable.SMS_MMS_TYPE), + values.getAsString(SmsMmsAnalyticsTable.RAT), + values.getAsString(SmsMmsAnalyticsTable.SLOT_ID), + values.getAsString(SmsMmsAnalyticsTable.FAILURE_REASON), + values.getAsString(SmsMmsAnalyticsTable.RELEASE_VERSION) + }; + cursor = + mTelephonyAnalyticsUtil.getCursor( + SmsMmsAnalyticsTable.TABLE_NAME, + SMS_MMS_INSERTION_PROJECTION, + SMS_MMS_INSERTION_FAILURE_SELECTION, + selectionArgs, + null, + null, + null, + null); + } + updateIfEntryExistsOtherwiseInsert(cursor, values); + deleteOldAndOverflowData(); + } catch (Exception e) { + Rlog.e(TAG, "Exception during Sms/Mms Insertion [insertDataToDb()] " + e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + + } + + /** + * Checks if a similar entry exists and updates the existing entry. Otherwise, inserts a new + * entry. + */ + @VisibleForTesting + public void updateIfEntryExistsOtherwiseInsert(Cursor cursor, ContentValues values) { + if (cursor != null && cursor.moveToFirst()) { + int idColumnIndex = cursor.getColumnIndex(SmsMmsAnalyticsTable._ID); + int countColumnIndex = cursor.getColumnIndex(SmsMmsAnalyticsTable.COUNT); + if (idColumnIndex != -1 && countColumnIndex != -1) { + int id = cursor.getInt(idColumnIndex); + int count = cursor.getInt(countColumnIndex); + int newCount = count + 1; + + values.put(SmsMmsAnalyticsTable.COUNT, newCount); + + String updateSelection = SmsMmsAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {String.valueOf(id)}; + Rlog.d(TAG, "Updated Count = " + values.getAsString(SmsMmsAnalyticsTable.COUNT)); + + mTelephonyAnalyticsUtil.update( + SmsMmsAnalyticsTable.TABLE_NAME, + values, + updateSelection, + updateSelectionArgs); + } + } else { + mTelephonyAnalyticsUtil.insert(SmsMmsAnalyticsTable.TABLE_NAME, values); + } + } + + /** Gets the count from the cursor */ + @VisibleForTesting + public long getCount(String[] columns, String selection, String[] selectionArgs) { + Cursor cursor = null; + long count = 0; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + SmsMmsAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + null, + null, + null, + null); + count = mTelephonyAnalyticsUtil.getCountFromCursor(cursor); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return count; + } + + private long getSmsMmsOfTypeAndStatus(String smsMmsType, String smsMmsStatus) { + String[] columns = {"SUM(" + SmsMmsAnalyticsTable.COUNT + ")"}; + String selection = SmsMmsAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + + if (smsMmsType != null && smsMmsStatus != null) { + selection = + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + SmsMmsAnalyticsTable.SLOT_ID + + " = ? "; + selectionArgs = new String[] {smsMmsType, smsMmsStatus, Integer.toString(mSlotIndex)}; + } else if (smsMmsType != null) { + selection = + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + SmsMmsAnalyticsTable.SLOT_ID + + " = ? "; + selectionArgs = new String[] {smsMmsType, Integer.toString(mSlotIndex)}; + } else if (smsMmsStatus != null) { + selection = + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + SmsMmsAnalyticsTable.SLOT_ID + + " = ? "; + selectionArgs = new String[] {smsMmsStatus, Integer.toString(mSlotIndex)}; + } + return getCount(columns, selection, selectionArgs); + } + + private long getSmsOutgoingCount() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.SMS_OUTGOING.value, null); + } + + private long getSmsIncomingCount() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.SMS_INCOMING.value, null); + } + + private long getMmsOutgoingCount() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.MMS_OUTGOING.value, null); + } + + private long getMmsIncomingCount() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.MMS_INCOMING.value, null); + } + + private long getFailedOutgoingSms() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.SMS_OUTGOING.value, SmsMmsStatus.FAILURE.value); + } + + private long getFailedIncomingSms() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.SMS_INCOMING.value, SmsMmsStatus.FAILURE.value); + } + + private long getFailedOutgoingMms() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.MMS_OUTGOING.value, SmsMmsStatus.FAILURE.value); + } + + private long getFailedIncomingMms() { + return getSmsMmsOfTypeAndStatus(SmsMmsType.MMS_INCOMING.value, SmsMmsStatus.FAILURE.value); + } + + private HashMap<String, Integer> getSmsFailedCountByRat() { + HashMap<String, Integer> failedSmsTypeCountByRat = new HashMap<>(); + String[] columns = { + SmsMmsAnalyticsTable.RAT, "SUM(" + SmsMmsAnalyticsTable.COUNT + ") as count " + }; + String selection = + SmsMmsAnalyticsTable.SLOT_ID + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " IN ('" + + SmsMmsType.SMS_INCOMING.value + + "', '" + + SmsMmsType.SMS_OUTGOING.value + + "' ) "; + String[] selectionArgs = {Integer.toString(mSlotIndex), SmsMmsStatus.FAILURE.value}; + String groupBy = SmsMmsAnalyticsTable.RAT; + Cursor cursor = null; + try { + cursor = + mTelephonyAnalyticsUtil.getCursor( + SmsMmsAnalyticsTable.TABLE_NAME, + columns, + selection, + selectionArgs, + groupBy, + null, + null, + null); + if (cursor != null) { + int ratIndex = cursor.getColumnIndex(SmsMmsAnalyticsTable.RAT); + int countIndex = cursor.getColumnIndex("count"); + + if (ratIndex != -1 && countIndex != -1) { + while (cursor.moveToNext()) { + String rat = cursor.getString(ratIndex); + int count = cursor.getInt(countIndex); + failedSmsTypeCountByRat.put(rat, count); + } + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return failedSmsTypeCountByRat; + } + + protected void deleteOldAndOverflowData() { + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + if (mDateOfDeletedRecordsSmsMmsTable == null + || !mDateOfDeletedRecordsSmsMmsTable.equals(dateToday)) { + mTelephonyAnalyticsUtil.deleteOverflowAndOldData( + SmsMmsAnalyticsTable.TABLE_NAME, + SMS_MMS_OVERFLOW_DATA_DELETION_SELECTION, + SMS_MMS_OLD_DATA_DELETION_SELECTION); + mDateOfDeletedRecordsSmsMmsTable = dateToday; + } + } + + /** Setter function for mDateOfDeletedRecordsSmsMmsTable for testing purposes */ + public void setDateOfDeletedRecordsSmsMmsTable(String deletedDate) { + mDateOfDeletedRecordsSmsMmsTable = deletedDate; + } + + /** + * Sets all the received information in a list along with the associated String description. + * + * @return A list of all the information with their respective description. + */ + @VisibleForTesting + public ArrayList<String> dumpInformationInList( + long totalOutgoingSms, + long totalIncomingSms, + long failedOutgoingSms, + long failedIncomingSms, + long totalOutgoingMms, + long totalIncomingMms, + double percentageFailureOutgoingSms, + double percentageFailureIncomingSms, + double percentageFailureOutgoingMms, + double percentageFailureIncomingMms, + HashMap<String, Integer> failedSmsTypeCountByRat) { + + ArrayList<String> aggregatedSmsMmsInformation = new ArrayList<>(); + aggregatedSmsMmsInformation.add("Total Outgoing Sms Count = " + totalOutgoingSms); + aggregatedSmsMmsInformation.add("Total Incoming Sms Count = " + totalIncomingSms); + aggregatedSmsMmsInformation.add( + "Failed Outgoing SMS Count = " + + failedOutgoingSms + + " Percentage failure rate for Outgoing SMS :" + + DECIMAL_FORMAT.format(percentageFailureOutgoingSms) + + "%"); + aggregatedSmsMmsInformation.add( + "Failed Incoming SMS Count = " + + failedIncomingSms + + " Percentage failure rate for Incoming SMS :" + + DECIMAL_FORMAT.format(percentageFailureIncomingSms) + + "%"); + + double overallFailPercentage = + (double) (failedIncomingSms + failedOutgoingSms) + / (double) (totalIncomingSms + totalOutgoingSms) + * 100.0; + aggregatedSmsMmsInformation.add( + "Overall Fail Percentage = " + DECIMAL_FORMAT.format(overallFailPercentage) + "%"); + try { + failedSmsTypeCountByRat.forEach( + (k, v) -> { + double percentageFail = + ((double) v + / (double) (totalIncomingSms + totalOutgoingSms) + * 100.0); + aggregatedSmsMmsInformation.add( + "Failed SMS Count for RAT : " + + k + + " = " + + v + + ", Percentage = " + + DECIMAL_FORMAT.format(percentageFail) + + "%"); + }); + + } catch (Exception e) { + Rlog.d(TAG, "Exception in adding to List = " + e); + } + + return aggregatedSmsMmsInformation; + } + + /** + * Gathers all the necessary information for the report by using specific methods. + * + * @return List of SmsMms analytics information. + */ + public ArrayList<String> aggregate() { + long totalOutgoingSms = getSmsOutgoingCount(); + long totalIncomingSms = getSmsIncomingCount(); + long totalOutgoingMms = getMmsOutgoingCount(); + long totalIncomingMms = getMmsIncomingCount(); + long totalFailedOutgoingSms = getFailedOutgoingSms(); + long totalFailedIncomingSms = getFailedIncomingSms(); + long totalFailedOutgoingMms = getFailedOutgoingMms(); + long totalFailedIncomingMms = getFailedIncomingMms(); + HashMap<String, Integer> failedSmsTypeCountByRat = getSmsFailedCountByRat(); + + double percentageFailureOutgoingSms = + totalOutgoingSms != 0 + ? (double) totalFailedOutgoingSms / totalOutgoingSms * 100.0 + : 0; + double percentageFailureIncomingSms = + totalIncomingSms != 0 + ? (double) totalFailedIncomingSms / totalIncomingSms * 100.0 + : 0; + + double percentageFailureOutgoingMms = + totalOutgoingMms != 0 + ? (double) totalFailedOutgoingMms / totalOutgoingMms * 100.0 + : 0; + double percentageFailureIncomingMms = + totalIncomingMms != 0 + ? (double) totalFailedIncomingMms / totalIncomingMms * 100.0 + : 0; + + return dumpInformationInList( + totalOutgoingSms, + totalIncomingSms, + totalFailedOutgoingSms, + totalFailedIncomingSms, + totalOutgoingMms, + totalIncomingMms, + percentageFailureOutgoingSms, + percentageFailureIncomingSms, + percentageFailureOutgoingMms, + percentageFailureIncomingMms, + failedSmsTypeCountByRat); + } +} diff --git a/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java b/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java new file mode 100644 index 0000000000..d7a70be565 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/TelephonyAnalytics.java @@ -0,0 +1,1200 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static com.android.internal.telephony.InboundSmsHandler.SOURCE_INJECTED_FROM_IMS; +import static com.android.internal.telephony.InboundSmsHandler.SOURCE_INJECTED_FROM_UNKNOWN; +import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_GENERIC; +import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_NOT_SUPPORTED; +import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_ERROR_NO_MEMORY; +import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS__ERROR__SMS_SUCCESS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.SystemClock; +import android.provider.Settings; +import android.provider.Telephony.Sms.Intents; +import android.telephony.Annotation; +import android.telephony.DisconnectCause; +import android.telephony.ServiceState; +import android.telephony.SmsManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.stub.ImsRegistrationImplBase; + +import com.android.internal.telephony.InboundSmsHandler; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Class to handle all telephony analytics related operations Initializes all the Analytics, + * Provider and Util classes. Registers the required Callbacks for supporting the + * ServiceStateAnalytics , SMS Analytics and Call Analytics + */ +public class TelephonyAnalytics { + private static final String TAG = TelephonyAnalytics.class.getSimpleName(); + protected static final int INVALID_SUB_ID = -1; + private final int mSlotIndex; + private final HandlerThread mHandlerThread; + private final Handler mHandler; + private ExecutorService mExecutorService; + protected TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + protected int mSubId; + protected ServiceStateAnalytics mServiceStateAnalytics; + protected Context mContext; + protected Executor mExecutor; + protected SubscriptionManager mSubscriptionManager; + protected final SubscriptionManager.OnSubscriptionsChangedListener + mSubscriptionsChangeListener = + new SubscriptionManager.OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + int newSubId = getSubId(); + if ((mSubId != newSubId) + && (newSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { + stopAnalytics(mSubId); + mSubId = newSubId; + startAnalytics(newSubId); + Rlog.d( + TAG, + "Started Listener, mSubId = " + + mSubId + + "SlotId = " + + mSlotIndex); + } + } + }; + protected CallAnalyticsProvider mCallAnalyticsProvider; + protected SmsMmsAnalyticsProvider mSmsMmsAnalyticsProvider; + protected ServiceStateAnalyticsProvider mServiceStateAnalyticsProvider; + protected SmsMmsAnalytics mSmsMmsAnalytics; + protected CallAnalytics mCallAnalytics; + protected Phone mPhone; + + public TelephonyAnalytics(Phone phone) { + mPhone = phone; + mContext = mPhone.getContext(); + mExecutor = Runnable::run; + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mSlotIndex = mPhone.getPhoneId(); + + mHandlerThread = new HandlerThread(TelephonyAnalytics.class.getSimpleName()); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mExecutorService = Executors.newSingleThreadExecutor(); + mTelephonyAnalyticsUtil = TelephonyAnalyticsUtil.getInstance(mContext); + initializeAnalyticsClasses(); + mCallAnalyticsProvider = new CallAnalyticsProvider(mTelephonyAnalyticsUtil, mSlotIndex); + mSmsMmsAnalyticsProvider = new SmsMmsAnalyticsProvider(mTelephonyAnalyticsUtil, mSlotIndex); + mServiceStateAnalyticsProvider = + new ServiceStateAnalyticsProvider(mTelephonyAnalyticsUtil, mSlotIndex); + + startAnalytics(mSubId); + + if (mSubscriptionManager != null) { + mSubscriptionManager.addOnSubscriptionsChangedListener( + mExecutor, mSubscriptionsChangeListener); + Rlog.d(TAG, "stopped listener"); + } + } + + @SuppressLint("MissingPermission") + private int getSubId() { + int subId = INVALID_SUB_ID; + try { + SubscriptionInfo info = + mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(mSlotIndex); + subId = info.getSubscriptionId(); + Rlog.d("TelephonyAnalyticsSubId", "SubId = " + subId + + "SlotIndex = " + mSlotIndex); + } catch (NullPointerException e) { + Rlog.e("TelephonyAnalyticsSubId", "Null Pointer Exception Caught"); + } + return subId; + } + + private void initializeAnalyticsClasses() { + mServiceStateAnalytics = new ServiceStateAnalytics(mExecutor); + mSmsMmsAnalytics = new SmsMmsAnalytics(); + mCallAnalytics = new CallAnalytics(); + } + + protected void startAnalytics(int subId) { + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + Rlog.d( + "StartAnalytics", + "Invalid SubId = " + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + return; + } + mServiceStateAnalytics.registerMyListener(mContext, subId); + } + + protected void stopAnalytics(int subId) { + if (mServiceStateAnalytics != null) { + mServiceStateAnalytics.unregisterMyListener(subId); + } + } + + public SmsMmsAnalytics getSmsMmsAnalytics() { + return mSmsMmsAnalytics; + } + + public CallAnalytics getCallAnalytics() { + return mCallAnalytics; + } + + /** + * Uses the provider class objects,collects the aggregated report from the respective provider + * classes. Dumps the collected stats in the bugreport. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + pw.println("+ Telephony Analytics Report [2 months] [Slot ID = " + mSlotIndex + "] +"); + pw.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + pw.println("Call Analytics Summary"); + ArrayList<String> aggregatedCallInfo = mCallAnalyticsProvider.aggregate(); + for (String info : aggregatedCallInfo) { + pw.println("\t" + info); + } + pw.println("-----------------------------------------------"); + pw.println("SMS/MMS Analytics Summary"); + ArrayList<String> aggregatedSmsMmsInfo = mSmsMmsAnalyticsProvider.aggregate(); + for (String info : aggregatedSmsMmsInfo) { + pw.println("\t\t" + info); + } + pw.println("-----------------------------------------------"); + mServiceStateAnalytics.recordCurrentStateBeforeDump(); + pw.println("Service State Analytics Summary "); + ArrayList<String> aggregatedServiceStateInfo = mServiceStateAnalyticsProvider.aggregate(); + for (String info : aggregatedServiceStateInfo) { + pw.println("\t\t" + info); + } + pw.println("-----------------------------------------------"); + } + + /** + * Provides implementation for processing received Call related data. It implements functions to + * handle various scenarios pertaining to Calls. Passes the data to its provider class + * for further processing. + */ + public class CallAnalytics { + private static final String TAG = CallAnalytics.class.getSimpleName(); + + private enum Status { + SUCCESS("Success"), + FAILURE("Failure"); + public String value; + + Status(String value) { + this.value = value; + } + } + + private enum CallType { + NORMAL_CALL("Normal Call"), + SOS_CALL("SOS Call"); + public String value; + + CallType(String value) { + this.value = value; + } + } + + public CallAnalytics() {} + + /** + * Collects and processes data related to calls once the call is terminated. + * + * @param isEmergency : Stores whether the call is an SOS call or not + * @param isOverIms : Stores whether the call is over IMS. + * @param rat : Stores the Radio Access Technology being used when the call ended + * @param simSlotIndex : Sim Slot from which call was operating. + * @param disconnectCause : Reason for call disconnect. + */ + public void onCallTerminated( + boolean isEmergency, + boolean isOverIms, + int rat, + int simSlotIndex, + int disconnectCause) { + String disconnectCauseString; + String status; + String callType; + if (isEmergency) { + callType = CallType.SOS_CALL.value; + } else { + callType = CallType.NORMAL_CALL.value; + } + if (isOverIms) { + disconnectCauseString = sImsCodeMap.get(disconnectCause); + status = + disconnectCause == ImsReasonInfo.CODE_USER_TERMINATED + || disconnectCause + == ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE + ? Status.SUCCESS.value + : Status.FAILURE.value; + } else { + disconnectCauseString = DisconnectCause.toString(disconnectCause); + status = + disconnectCause == DisconnectCause.LOCAL + || disconnectCause == DisconnectCause.NORMAL + ? Status.SUCCESS.value + : Status.FAILURE.value; + } + String ratString = TelephonyManager.getNetworkTypeName(rat); + sendDataToProvider(callType, status, simSlotIndex, rat, ratString, + disconnectCause, disconnectCauseString); + } + + private void sendDataToProvider(String callType, String status, int simSlotIndex, + int rat, String ratString, int disconnectCause, String disconnectCauseString) { + mExecutorService.execute(() -> { + mCallAnalyticsProvider.insertDataToDb( + callType, status, simSlotIndex, ratString, disconnectCauseString); + ArrayList<String> data; + data = + new ArrayList<>( + List.of( + callType, + status, + disconnectCauseString, + "(" + disconnectCause + ")", + ratString, + "(" + rat + ")", + Integer.toString(simSlotIndex))); + Rlog.d(TAG, data.toString()); + }); + } + + private static final Map<Integer, String> sImsCodeMap; + + static { + sImsCodeMap = new HashMap<>(); + sImsCodeMap.put(ImsReasonInfo.CODE_UNSPECIFIED, "CODE_UNSPECIFIED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT, "CODE_LOCAL_ILLEGAL_ARGUMENT"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_ILLEGAL_STATE, "CODE_LOCAL_ILLEGAL_STATE"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR, "CODE_LOCAL_INTERNAL_ERROR"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, "CODE_LOCAL_IMS_SERVICE_DOWN"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL, "CODE_LOCAL_NO_PENDING_CALL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE, + "CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_POWER_OFF, "CODE_LOCAL_POWER_OFF"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY, "CODE_LOCAL_LOW_BATTERY"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE, "CODE_LOCAL_NETWORK_NO_SERVICE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, + "CODE_LOCAL_NETWORK_NO_LTE_COVERAGE"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_NETWORK_ROAMING, "CODE_LOCAL_NETWORK_ROAMING"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_NETWORK_IP_CHANGED, "CODE_LOCAL_NETWORK_IP_CHANGED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE, "CODE_LOCAL_SERVICE_UNAVAILABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, "CODE_LOCAL_NOT_REGISTERED"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_CALL_EXCEEDED, "CODE_LOCAL_CALL_EXCEEDED"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_CALL_BUSY, "CODE_LOCAL_CALL_BUSY"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_CALL_DECLINE, "CODE_LOCAL_CALL_DECLINE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_CALL_VCC_ON_PROGRESSING, + "CODE_LOCAL_CALL_VCC_ON_PROGRESSING"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED, + "CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED, + "CODE_LOCAL_CALL_CS_RETRY_REQUIRED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED, + "CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_CALL_TERMINATED, "CODE_LOCAL_CALL_TERMINATED"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOCAL_HO_NOT_FEASIBLE, "CODE_LOCAL_HO_NOT_FEASIBLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_TIMEOUT_1XX_WAITING, "CODE_TIMEOUT_1XX_WAITING"); + sImsCodeMap.put(ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER, "CODE_TIMEOUT_NO_ANSWER"); + sImsCodeMap.put( + ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE, + "CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE"); + sImsCodeMap.put(ImsReasonInfo.CODE_CALL_BARRED, "CODE_CALL_BARRED"); + sImsCodeMap.put(ImsReasonInfo.CODE_FDN_BLOCKED, "CODE_FDN_BLOCKED"); + sImsCodeMap.put(ImsReasonInfo.CODE_IMEI_NOT_ACCEPTED, "CODE_IMEI_NOT_ACCEPTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_DIAL_MODIFIED_TO_USSD, "CODE_DIAL_MODIFIED_TO_USSD"); + sImsCodeMap.put(ImsReasonInfo.CODE_DIAL_MODIFIED_TO_SS, "CODE_DIAL_MODIFIED_TO_SS"); + sImsCodeMap.put(ImsReasonInfo.CODE_DIAL_MODIFIED_TO_DIAL, "CODE_DIAL_MODIFIED_TO_DIAL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_DIAL_MODIFIED_TO_DIAL_VIDEO, + "CODE_DIAL_MODIFIED_TO_DIAL_VIDEO"); + sImsCodeMap.put( + ImsReasonInfo.CODE_DIAL_VIDEO_MODIFIED_TO_DIAL, + "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO, + "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO"); + sImsCodeMap.put( + ImsReasonInfo.CODE_DIAL_VIDEO_MODIFIED_TO_SS, "CODE_DIAL_VIDEO_MODIFIED_TO_SS"); + sImsCodeMap.put( + ImsReasonInfo.CODE_DIAL_VIDEO_MODIFIED_TO_USSD, + "CODE_DIAL_VIDEO_MODIFIED_TO_USSD"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_REDIRECTED, "CODE_SIP_REDIRECTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_BAD_REQUEST, "CODE_SIP_BAD_REQUEST"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_FORBIDDEN, "CODE_SIP_FORBIDDEN"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_NOT_FOUND, "CODE_SIP_NOT_FOUND"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_NOT_SUPPORTED, "CODE_SIP_NOT_SUPPORTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_REQUEST_TIMEOUT, "CODE_SIP_REQUEST_TIMEOUT"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_TEMPRARILY_UNAVAILABLE, + "CODE_SIP_TEMPRARILY_UNAVAILABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_BAD_ADDRESS, "CODE_SIP_BAD_ADDRESS"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_BUSY, "CODE_SIP_BUSY"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_REQUEST_CANCELLED, "CODE_SIP_REQUEST_CANCELLED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_NOT_ACCEPTABLE, "CODE_SIP_NOT_ACCEPTABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_NOT_REACHABLE, "CODE_SIP_NOT_REACHABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_CLIENT_ERROR, "CODE_SIP_CLIENT_ERROR"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_TRANSACTION_DOES_NOT_EXIST, + "CODE_SIP_TRANSACTION_DOES_NOT_EXIST"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_SERVER_INTERNAL_ERROR, "CODE_SIP_SERVER_INTERNAL_ERROR"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_SERVICE_UNAVAILABLE, "CODE_SIP_SERVICE_UNAVAILABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_SERVER_TIMEOUT, "CODE_SIP_SERVER_TIMEOUT"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_SERVER_ERROR, "CODE_SIP_SERVER_ERROR"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_USER_REJECTED, "CODE_SIP_USER_REJECTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_GLOBAL_ERROR, "CODE_SIP_GLOBAL_ERROR"); + sImsCodeMap.put( + ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE, "CODE_EMERGENCY_TEMP_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE, "CODE_EMERGENCY_PERM_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_USER_MARKED_UNWANTED, "CODE_SIP_USER_MARKED_UNWANTED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_METHOD_NOT_ALLOWED, "CODE_SIP_METHOD_NOT_ALLOWED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_PROXY_AUTHENTICATION_REQUIRED, + "CODE_SIP_PROXY_AUTHENTICATION_REQUIRED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_REQUEST_ENTITY_TOO_LARGE, + "CODE_SIP_REQUEST_ENTITY_TOO_LARGE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_REQUEST_URI_TOO_LARGE, "CODE_SIP_REQUEST_URI_TOO_LARGE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_EXTENSION_REQUIRED, "CODE_SIP_EXTENSION_REQUIRED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_INTERVAL_TOO_BRIEF, "CODE_SIP_INTERVAL_TOO_BRIEF"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST, + "CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_LOOP_DETECTED, "CODE_SIP_LOOP_DETECTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_TOO_MANY_HOPS, "CODE_SIP_TOO_MANY_HOPS"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_AMBIGUOUS, "CODE_SIP_AMBIGUOUS"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_REQUEST_PENDING, "CODE_SIP_REQUEST_PENDING"); + sImsCodeMap.put(ImsReasonInfo.CODE_SIP_UNDECIPHERABLE, "CODE_SIP_UNDECIPHERABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_MEDIA_INIT_FAILED, "CODE_MEDIA_INIT_FAILED"); + sImsCodeMap.put(ImsReasonInfo.CODE_MEDIA_NO_DATA, "CODE_MEDIA_NO_DATA"); + sImsCodeMap.put(ImsReasonInfo.CODE_MEDIA_NOT_ACCEPTABLE, "CODE_MEDIA_NOT_ACCEPTABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_MEDIA_UNSPECIFIED, "CODE_MEDIA_UNSPECIFIED"); + sImsCodeMap.put(ImsReasonInfo.CODE_USER_TERMINATED, "CODE_USER_TERMINATED"); + sImsCodeMap.put(ImsReasonInfo.CODE_USER_NOANSWER, "CODE_USER_NOANSWER"); + sImsCodeMap.put(ImsReasonInfo.CODE_USER_IGNORE, "CODE_USER_IGNORE"); + sImsCodeMap.put(ImsReasonInfo.CODE_USER_DECLINE, "CODE_USER_DECLINE"); + sImsCodeMap.put(ImsReasonInfo.CODE_LOW_BATTERY, "CODE_LOW_BATTERY"); + sImsCodeMap.put(ImsReasonInfo.CODE_BLACKLISTED_CALL_ID, "CODE_BLACKLISTED_CALL_ID"); + sImsCodeMap.put( + ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, "CODE_USER_TERMINATED_BY_REMOTE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_USER_REJECTED_SESSION_MODIFICATION, + "CODE_USER_REJECTED_SESSION_MODIFICATION"); + sImsCodeMap.put( + ImsReasonInfo.CODE_USER_CANCELLED_SESSION_MODIFICATION, + "CODE_USER_CANCELLED_SESSION_MODIFICATION"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SESSION_MODIFICATION_FAILED, + "CODE_SESSION_MODIFICATION_FAILED"); + sImsCodeMap.put(ImsReasonInfo.CODE_UT_NOT_SUPPORTED, "CODE_UT_NOT_SUPPORTED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE, "CODE_UT_SERVICE_UNAVAILABLE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_OPERATION_NOT_ALLOWED, "CODE_UT_OPERATION_NOT_ALLOWED"); + sImsCodeMap.put(ImsReasonInfo.CODE_UT_NETWORK_ERROR, "CODE_UT_NETWORK_ERROR"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH, "CODE_UT_CB_PASSWORD_MISMATCH"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL, "CODE_UT_SS_MODIFIED_TO_DIAL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_USSD, "CODE_UT_SS_MODIFIED_TO_USSD"); + sImsCodeMap.put(ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_SS, "CODE_UT_SS_MODIFIED_TO_SS"); + sImsCodeMap.put( + ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO, + "CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO"); + sImsCodeMap.put(ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED, "CODE_ECBM_NOT_SUPPORTED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED, + "CODE_MULTIENDPOINT_NOT_SUPPORTED"); + sImsCodeMap.put(ImsReasonInfo.CODE_REGISTRATION_ERROR, "CODE_REGISTRATION_ERROR"); + sImsCodeMap.put(ImsReasonInfo.CODE_ANSWERED_ELSEWHERE, "CODE_ANSWERED_ELSEWHERE"); + sImsCodeMap.put(ImsReasonInfo.CODE_CALL_PULL_OUT_OF_SYNC, "CODE_CALL_PULL_OUT_OF_SYNC"); + sImsCodeMap.put( + ImsReasonInfo.CODE_CALL_END_CAUSE_CALL_PULL, "CODE_CALL_END_CAUSE_CALL_PULL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE, + "CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE"); + sImsCodeMap.put(ImsReasonInfo.CODE_REJECTED_ELSEWHERE, "CODE_REJECTED_ELSEWHERE"); + sImsCodeMap.put(ImsReasonInfo.CODE_SUPP_SVC_FAILED, "CODE_SUPP_SVC_FAILED"); + sImsCodeMap.put(ImsReasonInfo.CODE_SUPP_SVC_CANCELLED, "CODE_SUPP_SVC_CANCELLED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SUPP_SVC_REINVITE_COLLISION, + "CODE_SUPP_SVC_REINVITE_COLLISION"); + sImsCodeMap.put(ImsReasonInfo.CODE_IWLAN_DPD_FAILURE, "CODE_IWLAN_DPD_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_EPDG_TUNNEL_ESTABLISH_FAILURE, + "CODE_EPDG_TUNNEL_ESTABLISH_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_EPDG_TUNNEL_REKEY_FAILURE, "CODE_EPDG_TUNNEL_REKEY_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_EPDG_TUNNEL_LOST_CONNECTION, + "CODE_EPDG_TUNNEL_LOST_CONNECTION"); + sImsCodeMap.put( + ImsReasonInfo.CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED, + "CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED"); + sImsCodeMap.put(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE, "CODE_REMOTE_CALL_DECLINE"); + sImsCodeMap.put(ImsReasonInfo.CODE_DATA_LIMIT_REACHED, "CODE_DATA_LIMIT_REACHED"); + sImsCodeMap.put(ImsReasonInfo.CODE_DATA_DISABLED, "CODE_DATA_DISABLED"); + sImsCodeMap.put(ImsReasonInfo.CODE_WIFI_LOST, "CODE_WIFI_LOST"); + sImsCodeMap.put(ImsReasonInfo.CODE_IKEV2_AUTH_FAILURE, "CODE_IKEV2_AUTH_FAILURE"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_OFF, "CODE_RADIO_OFF"); + sImsCodeMap.put(ImsReasonInfo.CODE_NO_VALID_SIM, "CODE_NO_VALID_SIM"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_INTERNAL_ERROR, "CODE_RADIO_INTERNAL_ERROR"); + sImsCodeMap.put(ImsReasonInfo.CODE_NETWORK_RESP_TIMEOUT, "CODE_NETWORK_RESP_TIMEOUT"); + sImsCodeMap.put(ImsReasonInfo.CODE_NETWORK_REJECT, "CODE_NETWORK_REJECT"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_ACCESS_FAILURE, "CODE_RADIO_ACCESS_FAILURE"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_LINK_FAILURE, "CODE_RADIO_LINK_FAILURE"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_LINK_LOST, "CODE_RADIO_LINK_LOST"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_UPLINK_FAILURE, "CODE_RADIO_UPLINK_FAILURE"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_SETUP_FAILURE, "CODE_RADIO_SETUP_FAILURE"); + sImsCodeMap.put(ImsReasonInfo.CODE_RADIO_RELEASE_NORMAL, "CODE_RADIO_RELEASE_NORMAL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_RADIO_RELEASE_ABNORMAL, "CODE_RADIO_RELEASE_ABNORMAL"); + sImsCodeMap.put(ImsReasonInfo.CODE_ACCESS_CLASS_BLOCKED, "CODE_ACCESS_CLASS_BLOCKED"); + sImsCodeMap.put(ImsReasonInfo.CODE_NETWORK_DETACH, "CODE_NETWORK_DETACH"); + sImsCodeMap.put( + ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL, + "CODE_SIP_ALTERNATE_EMERGENCY_CALL"); + sImsCodeMap.put(ImsReasonInfo.CODE_UNOBTAINABLE_NUMBER, "CODE_UNOBTAINABLE_NUMBER"); + sImsCodeMap.put(ImsReasonInfo.CODE_NO_CSFB_IN_CS_ROAM, "CODE_NO_CSFB_IN_CS_ROAM"); + sImsCodeMap.put(ImsReasonInfo.CODE_REJECT_UNKNOWN, "CODE_REJECT_UNKNOWN"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CALL_WAITING_DISABLED, + "CODE_REJECT_ONGOING_CALL_WAITING_DISABLED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_CALL_ON_OTHER_SUB, "CODE_REJECT_CALL_ON_OTHER_SUB"); + sImsCodeMap.put(ImsReasonInfo.CODE_REJECT_1X_COLLISION, "CODE_REJECT_1X_COLLISION"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_SERVICE_NOT_REGISTERED, + "CODE_REJECT_SERVICE_NOT_REGISTERED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_CALL_TYPE_NOT_ALLOWED, + "CODE_REJECT_CALL_TYPE_NOT_ALLOWED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_E911_CALL, "CODE_REJECT_ONGOING_E911_CALL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CALL_SETUP, "CODE_REJECT_ONGOING_CALL_SETUP"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_MAX_CALL_LIMIT_REACHED, + "CODE_REJECT_MAX_CALL_LIMIT_REACHED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_UNSUPPORTED_SIP_HEADERS, + "CODE_REJECT_UNSUPPORTED_SIP_HEADERS"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_UNSUPPORTED_SDP_HEADERS, + "CODE_REJECT_UNSUPPORTED_SDP_HEADERS"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CALL_TRANSFER, + "CODE_REJECT_ONGOING_CALL_TRANSFER"); + sImsCodeMap.put(ImsReasonInfo.CODE_REJECT_INTERNAL_ERROR, "CODE_REJECT_INTERNAL_ERROR"); + sImsCodeMap.put(ImsReasonInfo.CODE_REJECT_QOS_FAILURE, "CODE_REJECT_QOS_FAILURE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_HANDOVER, "CODE_REJECT_ONGOING_HANDOVER"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_VT_TTY_NOT_ALLOWED, "CODE_REJECT_VT_TTY_NOT_ALLOWED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CALL_UPGRADE, + "CODE_REJECT_ONGOING_CALL_UPGRADE"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED, + "CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CONFERENCE_CALL, + "CODE_REJECT_ONGOING_CONFERENCE_CALL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_VT_AVPF_NOT_ALLOWED, + "CODE_REJECT_VT_AVPF_NOT_ALLOWED"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_ENCRYPTED_CALL, + "CODE_REJECT_ONGOING_ENCRYPTED_CALL"); + sImsCodeMap.put( + ImsReasonInfo.CODE_REJECT_ONGOING_CS_CALL, "CODE_REJECT_ONGOING_CS_CALL"); + sImsCodeMap.put(ImsReasonInfo.CODE_NETWORK_CONGESTION, "CODE_NETWORK_CONGESTION"); + sImsCodeMap.put( + ImsReasonInfo.CODE_RETRY_ON_IMS_WITHOUT_RTT, "CODE_RETRY_ON_IMS_WITHOUT_RTT"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_1, "CODE_OEM_CAUSE_1"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_2, "CODE_OEM_CAUSE_2"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_3, "CODE_OEM_CAUSE_3"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_4, "CODE_OEM_CAUSE_4"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_5, "CODE_OEM_CAUSE_5"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_6, "CODE_OEM_CAUSE_6"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_7, "CODE_OEM_CAUSE_7"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_8, "CODE_OEM_CAUSE_8"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_9, "CODE_OEM_CAUSE_9"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_10, "CODE_OEM_CAUSE_10"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_11, "CODE_OEM_CAUSE_11"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_12, "CODE_OEM_CAUSE_12"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_13, "CODE_OEM_CAUSE_13"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_14, "CODE_OEM_CAUSE_14"); + sImsCodeMap.put(ImsReasonInfo.CODE_OEM_CAUSE_15, "CODE_OEM_CAUSE_15"); + } + } + + /** + * Implements and Registers the required Listeners and BroadcastReceivers for receiving + * ServiceState related information. Performs required logic on received data and then Passes + * the information to its provider class for further processing. + */ + public class ServiceStateAnalytics extends TelephonyCallback + implements TelephonyCallback.ServiceStateListener { + private final Executor mExecutor; + private static final String TAG = ServiceStateAnalytics.class.getSimpleName(); + private static final int BUFFER_TIME = 10000; + + private TelephonyManager mTelephonyManager; + + private enum DeviceStatus { + APM, + CELLULAR_OOS_WITH_IWLAN, + NO_NETWORK_COVERAGE, + SIM_ABSENT, + IN_SERVICE; + } + + private final AtomicReference<TimeStampedServiceState> mLastState = + new AtomicReference<>(null); + private static final String NA = "NA"; + private final BroadcastReceiver mBroadcastReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final long now = getTimeMillis(); + if (intent.getAction() + .equals(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED)) { + int simState = + intent.getIntExtra( + TelephonyManager.EXTRA_SIM_STATE, + TelephonyManager.SIM_STATE_UNKNOWN); + if (simState == TelephonyManager.SIM_STATE_ABSENT) { + Rlog.d("AnkitSimAbsent", "Sim is Absent"); + logSimAbsentState(); + } + } + } + }; + + protected ServiceStateAnalytics(Executor executor) { + super(); + mExecutor = executor; + IntentFilter mIntentFilter = + new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, mIntentFilter); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState serviceState) { + int dataRegState = serviceState.getDataRegState(); + int voiceRegState = serviceState.getVoiceRegState(); + int voiceRadioTechnology = serviceState.getRilVoiceRadioTechnology(); + int dataRadioTechnology = serviceState.getRilDataRadioTechnology(); + + mExecutorService.execute(() -> { + logServiceState(dataRegState, voiceRegState, voiceRadioTechnology, + dataRadioTechnology); + }); + } + + private void logServiceState( + int dataRegState, + int voiceRegState, + int voiceRadioTechnology, + int dataRadioTechnology) { + long now = getTimeMillis(); + String voiceRadioTechnologyName = + ServiceState.rilRadioTechnologyToString(voiceRadioTechnology); + String dataRadioTechnologyName = + ServiceState.rilRadioTechnologyToString(dataRadioTechnology); + + if (isAirplaneModeOn()) { + if (dataRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + && dataRegState == ServiceState.STATE_IN_SERVICE) { + logOosWithIwlan(now); + } else { + logAirplaneModeServiceState(now); + } + } else { + if (voiceRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN + && dataRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { + logNoNetworkCoverage(now); + + } else if (voiceRadioTechnology != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN + && dataRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { + if (voiceRegState == ServiceState.STATE_IN_SERVICE) { + logInServiceData(voiceRadioTechnologyName, now); + } else { + logNoNetworkCoverage(now); + } + } else if (voiceRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { + if (dataRegState == ServiceState.STATE_IN_SERVICE) { + if (dataRadioTechnology == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { + logOosWithIwlan(now); + } else { + logInServiceData(dataRadioTechnologyName, now); + } + } else { + logNoNetworkCoverage(now); + } + } else { + if (dataRegState == ServiceState.STATE_IN_SERVICE + || voiceRegState == ServiceState.STATE_IN_SERVICE) { + logInServiceData(voiceRadioTechnologyName, now); + } else { + logNoNetworkCoverage(now); + } + } + } + } + + private void logSimAbsentState() { + long now = getTimeMillis(); + TimeStampedServiceState currentState = + new TimeStampedServiceState( + mSlotIndex, NA, DeviceStatus.SIM_ABSENT.name(), now); + setCurrentStateAndAddLastState(currentState, now); + } + private void logOosWithIwlan(long now) { + TimeStampedServiceState currentState = + new TimeStampedServiceState(mSlotIndex, NA, + DeviceStatus.CELLULAR_OOS_WITH_IWLAN.name(), now); + setCurrentStateAndAddLastState(currentState, now); + } + + private void logAirplaneModeServiceState(long now) { + TimeStampedServiceState currentState = + new TimeStampedServiceState(mSlotIndex, NA, DeviceStatus.APM.name(), now); + setCurrentStateAndAddLastState(currentState, now); + } + + private void logNoNetworkCoverage(long now) { + TimeStampedServiceState currentState = + new TimeStampedServiceState( + mSlotIndex, NA, DeviceStatus.NO_NETWORK_COVERAGE.name(), now); + setCurrentStateAndAddLastState(currentState, now); + } + + private void logInServiceData(String rat, long now) { + TimeStampedServiceState currentState = + new TimeStampedServiceState( + mSlotIndex, rat, DeviceStatus.IN_SERVICE.name(), now); + setCurrentStateAndAddLastState(currentState, now); + } + + private void setCurrentStateAndAddLastState( + TimeStampedServiceState currentState, long now) { + TimeStampedServiceState lastState = mLastState.getAndSet(currentState); + addData(lastState, now); + } + + private void addData(TimeStampedServiceState lastState, long now) { + if (lastState == null) { + return; + } + if (now - lastState.mTimestampStart < BUFFER_TIME) { + return; + } + Rlog.d(TAG, "Last State = " + lastState.toString() + "End = " + now); + mServiceStateAnalyticsProvider.insertDataToDb(lastState, now); + } + + private void recordCurrentStateBeforeDump() { + long now = getTimeMillis(); + Rlog.d("RecordingStateBDump", "Recording " + now); + TimeStampedServiceState currentState = mLastState.get(); + mLastState.set(createCopyWithUpdatedTimestamp(currentState)); + addData(currentState, now); + } + + private TimeStampedServiceState createCopyWithUpdatedTimestamp( + TimeStampedServiceState currentState) { + if (currentState == null) { + return null; + } + long now = getTimeMillis(); + TimeStampedServiceState state = + new TimeStampedServiceState( + currentState.mSlotIndex, + currentState.mRAT, + currentState.mDeviceStatus, + now); + return state; + } + + private boolean isAirplaneModeOn() { + return Settings.Global.getInt( + mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) + != 0; + } + + protected long getTimeMillis() { + return SystemClock.elapsedRealtime(); + } + + void registerMyListener(Context context, int subId) { + try { + mTelephonyManager = + context.getSystemService(TelephonyManager.class) + .createForSubscriptionId(subId); + mTelephonyManager.registerTelephonyCallback(mExecutor, this); + + } catch (NullPointerException e) { + log("Null pointer exception caught " + e); + } + } + + void unregisterMyListener(int subId) { + mTelephonyManager.unregisterTelephonyCallback(this); + } + + private void log(String s) { + Rlog.d(ServiceStateAnalytics.class.getSimpleName(), s); + } + + /** + * Serves the functionality of storing service state related information, + * Along with the timestamp at which the state was detected. + */ + public static class TimeStampedServiceState { + protected final int mSlotIndex; + protected final String mRAT; + protected final String mDeviceStatus; + protected final long mTimestampStart; + + public TimeStampedServiceState( + int slotIndex, String rat, String deviceStatus, long timestampStart) { + mSlotIndex = slotIndex; + mRAT = rat; + mDeviceStatus = deviceStatus; + mTimestampStart = timestampStart; + } + + @Override + public String toString() { + return "SlotIndex = " + + mSlotIndex + + " RAT = " + + mRAT + + " DeviceStatus = " + + mDeviceStatus + + "TimeStampStart = " + + mTimestampStart; + } + /** Getter function for slotIndex */ + public int getSlotIndex() { + return mSlotIndex; + } + + /** Getter function for state start Timestamp */ + public long getTimestampStart() { + return mTimestampStart; + } + + /** Getter function for device Status */ + public String getDeviceStatus() { + return mDeviceStatus; + } + + /** Getter function for radio access technology */ + public String getRAT() { + return mRAT; + } + } + } + + /** + * Provides implementation for processing received Sms related data. Implements functions to + * handle various scenarios pertaining to Sms. Passes the data to its provider for further + * processing. + */ + public class SmsMmsAnalytics { + private static final String TAG = SmsMmsAnalytics.class.getSimpleName(); + public SmsMmsAnalytics() { + + } + + /** Collects Outgoing Sms related information. */ + public void onOutgoingSms(boolean isOverIms, @SmsManager.Result int sendErrorCode) { + Rlog.d( + TAG, + "Is Over Ims = " + + isOverIms + + " sendErrorCode = " + + sendErrorCode + + "SlotInfo =" + + mSlotIndex); + logOutgoingSms(isOverIms, sendErrorCode); + } + + /** Collects Successful Incoming Sms related information. */ + public void onIncomingSmsSuccess(@InboundSmsHandler.SmsSource int smsSource) { + Rlog.d(TAG, " smsSource = " + smsSource); + String status = "Success"; + String failureReason = "NA"; + logIncomingSms(smsSource, status, failureReason); + } + + /** Collects Failed Incoming Multipart Sms related information. */ + public void onDroppedIncomingMultipartSms() { + String status = "Failure"; + String type = "SMS Incoming"; + // Mark the RAT as unknown since it might have changed over time. + int rat = TelephonyManager.NETWORK_TYPE_UNKNOWN; + String ratString = ServiceState.rilRadioTechnologyToString(rat); + String failureReason = "INCOMING_SMS__ERROR__SMS_ERROR_GENERIC"; + sendDataToProvider(status, type, ratString, failureReason); + } + + /** Collects Failed Incoming Sms related information. */ + public void onIncomingSmsError(@InboundSmsHandler.SmsSource int smsSource, int result) { + String status = "Failure"; + String failureReason = getIncomingSmsErrorString(result); + logIncomingSms(smsSource, status, failureReason); + Rlog.d( + TAG, + " smsSource = " + + smsSource + + "Result = " + + result + + "IncomingError = " + + failureReason + + "(" + + getIncomingError(result) + + ")"); + } + + private void logOutgoingSms(boolean isOverIms, @SmsManager.Result int sendErrorCode) { + try { + String type = "SMS Outgoing"; + String status = sendErrorCode == 0 ? "Success" : "Failure"; + int rat = getRat(isOverIms); + String ratString = TelephonyManager.getNetworkTypeName(rat); + String failureReason = + status.equals("Success") ? "NA" : getSmsFailureReasonString(sendErrorCode); + Rlog.d( + TAG, + "SlotInfo = " + + mSlotIndex + + " Type = " + + type + + " Status = " + + status + + "RAT " + + ratString + + " " + + rat + + "Failure Reason = " + + failureReason); + sendDataToProvider(status, type, ratString, failureReason); + + } catch (Exception e) { + Rlog.d(TAG, "Error in SmsLogs" + e); + } + } + + private void logIncomingSms( + @InboundSmsHandler.SmsSource int smsSource, String status, String failureReason) { + String type = "SMS Incoming"; + try { + int rat = getRat(smsSource); + String ratString = TelephonyManager.getNetworkTypeName(rat); + sendDataToProvider(status, type, ratString, failureReason); + Rlog.d( + TAG, + "SlotInfo =" + + mSlotIndex + + " Type = " + + type + + " Status = " + + status + + " RAT " + + ratString + + " (" + + rat + + " ) Failure Reason = " + + failureReason); + } catch (Exception e) { + Rlog.e(TAG, "Exception = " + e); + } + } + + private void sendDataToProvider( + String status, String type, String rat, String failureReason) { + mExecutorService.execute(() -> { + mSmsMmsAnalyticsProvider.insertDataToDb(status, type, rat, failureReason); + }); + } + + private static int getIncomingError(int result) { + switch (result) { + case Activity.RESULT_OK: + case Intents.RESULT_SMS_HANDLED: + return INCOMING_SMS__ERROR__SMS_SUCCESS; + case Intents.RESULT_SMS_OUT_OF_MEMORY: + return INCOMING_SMS__ERROR__SMS_ERROR_NO_MEMORY; + case Intents.RESULT_SMS_UNSUPPORTED: + return INCOMING_SMS__ERROR__SMS_ERROR_NOT_SUPPORTED; + case Intents.RESULT_SMS_GENERIC_ERROR: + default: + return INCOMING_SMS__ERROR__SMS_ERROR_GENERIC; + } + } + + private static String getIncomingSmsErrorString(int result) { + switch (result) { + case Activity.RESULT_OK: + case Intents.RESULT_SMS_HANDLED: + return "INCOMING_SMS__ERROR__SMS_SUCCESS"; + case Intents.RESULT_SMS_OUT_OF_MEMORY: + return "INCOMING_SMS__ERROR__SMS_ERROR_NO_MEMORY"; + case Intents.RESULT_SMS_UNSUPPORTED: + return "INCOMING_SMS__ERROR__SMS_ERROR_NOT_SUPPORTED"; + case Intents.RESULT_SMS_GENERIC_ERROR: + default: + return "INCOMING_SMS__ERROR__SMS_ERROR_GENERIC"; + } + } + + @Nullable + private ServiceState getServiceState() { + Phone phone = mPhone; + if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { + phone = mPhone.getDefaultPhone(); + } + ServiceStateTracker serviceStateTracker = phone.getServiceStateTracker(); + return serviceStateTracker != null ? serviceStateTracker.getServiceState() : null; + } + + @Annotation.NetworkType + private int getRat(@InboundSmsHandler.SmsSource int smsSource) { + if (smsSource == SOURCE_INJECTED_FROM_UNKNOWN) { + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + return getRat(smsSource == SOURCE_INJECTED_FROM_IMS); + } + + @Annotation.NetworkType + private int getRat(boolean isOverIms) { + if (isOverIms) { + if (mPhone.getImsRegistrationTech() + == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN) { + return TelephonyManager.NETWORK_TYPE_IWLAN; + } + } + ServiceState serviceState = getServiceState(); + return serviceState != null + ? serviceState.getVoiceNetworkType() + : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + private String getSmsFailureReasonString(int sendErrorCode) { + switch (sendErrorCode) { + case SmsManager.RESULT_ERROR_NONE: + return "RESULT_ERROR_NONE"; + case SmsManager.RESULT_ERROR_GENERIC_FAILURE: + return "RESULT_ERROR_GENERIC_FAILURE"; + case SmsManager.RESULT_ERROR_RADIO_OFF: + return "RESULT_ERROR_RADIO_OFF"; + case SmsManager.RESULT_ERROR_NULL_PDU: + return "RESULT_ERROR_NULL_PDU"; + case SmsManager.RESULT_ERROR_NO_SERVICE: + return "RESULT_ERROR_NO_SERVICE"; + case SmsManager.RESULT_ERROR_LIMIT_EXCEEDED: + return "RESULT_ERROR_LIMIT_EXCEEDED"; + case SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE: + return "RESULT_ERROR_FDN_CHECK_FAILURE"; + case SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED: + return "RESULT_ERROR_SHORT_CODE_NOT_ALLOWED"; + case SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED: + return "RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED"; + case SmsManager.RESULT_RADIO_NOT_AVAILABLE: + return "RESULT_RADIO_NOT_AVAILABLE"; + case SmsManager.RESULT_NETWORK_REJECT: + return "RESULT_NETWORK_REJECT"; + case SmsManager.RESULT_INVALID_ARGUMENTS: + return "RESULT_INVALID_ARGUMENTS"; + case SmsManager.RESULT_INVALID_STATE: + return "RESULT_INVALID_STATE"; + case SmsManager.RESULT_NO_MEMORY: + return "RESULT_NO_MEMORY"; + case SmsManager.RESULT_INVALID_SMS_FORMAT: + return "RESULT_INVALID_SMS_FORMAT"; + case SmsManager.RESULT_SYSTEM_ERROR: + return "RESULT_SYSTEM_ERROR"; + case SmsManager.RESULT_MODEM_ERROR: + return "RESULT_MODEM_ERROR"; + case SmsManager.RESULT_NETWORK_ERROR: + return "RESULT_NETWORK_ERROR"; + case SmsManager.RESULT_INVALID_SMSC_ADDRESS: + return "RESULT_INVALID_SMSC_ADDRESS"; + case SmsManager.RESULT_OPERATION_NOT_ALLOWED: + return "RESULT_OPERATION_NOT_ALLOWED"; + case SmsManager.RESULT_INTERNAL_ERROR: + return "RESULT_INTERNAL_ERROR"; + case SmsManager.RESULT_NO_RESOURCES: + return "RESULT_NO_RESOURCES"; + case SmsManager.RESULT_CANCELLED: + return "RESULT_CANCELLED"; + case SmsManager.RESULT_REQUEST_NOT_SUPPORTED: + return "RESULT_REQUEST_NOT_SUPPORTED"; + case SmsManager.RESULT_NO_BLUETOOTH_SERVICE: + return "RESULT_NO_BLUETOOTH_SERVICE"; + case SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS: + return "RESULT_INVALID_BLUETOOTH_ADDRESS"; + case SmsManager.RESULT_BLUETOOTH_DISCONNECTED: + return "RESULT_BLUETOOTH_DISCONNECTED"; + case SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING: + return "RESULT_UNEXPECTED_EVENT_STOP_SENDING"; + case SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY: + return "RESULT_SMS_BLOCKED_DURING_EMERGENCY"; + case SmsManager.RESULT_SMS_SEND_RETRY_FAILED: + return "RESULT_SMS_SEND_RETRY_FAILED"; + case SmsManager.RESULT_REMOTE_EXCEPTION: + return "RESULT_REMOTE_EXCEPTION"; + case SmsManager.RESULT_NO_DEFAULT_SMS_APP: + return "RESULT_NO_DEFAULT_SMS_APP"; + case SmsManager.RESULT_USER_NOT_ALLOWED: + return "RESULT_USER_NOT_ALLOWED"; + case SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE: + return "RESULT_RIL_RADIO_NOT_AVAILABLE"; + case SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY: + return "RESULT_RIL_SMS_SEND_FAIL_RETRY"; + case SmsManager.RESULT_RIL_NETWORK_REJECT: + return "RESULT_RIL_NETWORK_REJECT"; + case SmsManager.RESULT_RIL_INVALID_STATE: + return "RESULT_RIL_INVALID_STATE"; + case SmsManager.RESULT_RIL_INVALID_ARGUMENTS: + return "RESULT_RIL_INVALID_ARGUMENTS"; + case SmsManager.RESULT_RIL_NO_MEMORY: + return "RESULT_RIL_NO_MEMORY"; + case SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED: + return "RESULT_RIL_REQUEST_RATE_LIMITED"; + case SmsManager.RESULT_RIL_INVALID_SMS_FORMAT: + return "RESULT_RIL_INVALID_SMS_FORMAT"; + case SmsManager.RESULT_RIL_SYSTEM_ERR: + return "RESULT_RIL_SYSTEM_ERR"; + case SmsManager.RESULT_RIL_ENCODING_ERR: + return "RESULT_RIL_ENCODING_ERR"; + case SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS: + return "RESULT_RIL_INVALID_SMSC_ADDRESS"; + case SmsManager.RESULT_RIL_MODEM_ERR: + return "RESULT_RIL_MODEM_ERR"; + case SmsManager.RESULT_RIL_NETWORK_ERR: + return "RESULT_RIL_NETWORK_ERR"; + case SmsManager.RESULT_RIL_INTERNAL_ERR: + return "RESULT_RIL_INTERNAL_ERR"; + case SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED: + return "RESULT_RIL_REQUEST_NOT_SUPPORTED"; + case SmsManager.RESULT_RIL_INVALID_MODEM_STATE: + return "RESULT_RIL_INVALID_MODEM_STATE"; + case SmsManager.RESULT_RIL_NETWORK_NOT_READY: + return "RESULT_RIL_NETWORK_NOT_READY"; + case SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED: + return "RESULT_RIL_OPERATION_NOT_ALLOWED"; + case SmsManager.RESULT_RIL_NO_RESOURCES: + return "RESULT_RIL_NO_RESOURCES"; + case SmsManager.RESULT_RIL_CANCELLED: + return "RESULT_RIL_CANCELLED"; + case SmsManager.RESULT_RIL_SIM_ABSENT: + return "RESULT_RIL_SIM_ABSENT"; + case SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED: + return "RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED"; + case SmsManager.RESULT_RIL_ACCESS_BARRED: + return "RESULT_RIL_ACCESS_BARRED"; + case SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL: + return "RESULT_RIL_BLOCKED_DUE_TO_CALL"; + case SmsManager.RESULT_RIL_GENERIC_ERROR: + return "RESULT_RIL_GENERIC_ERROR"; + case SmsManager.RESULT_RIL_INVALID_RESPONSE: + return "RESULT_RIL_INVALID_RESPONSE"; + case SmsManager.RESULT_RIL_SIM_PIN2: + return "RESULT_RIL_SIM_PIN2"; + case SmsManager.RESULT_RIL_SIM_PUK2: + return "RESULT_RIL_SIM_PUK2"; + case SmsManager.RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE: + return "RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE"; + case SmsManager.RESULT_RIL_SIM_ERROR: + return "RESULT_RIL_SIM_ERROR"; + case SmsManager.RESULT_RIL_INVALID_SIM_STATE: + return "RESULT_RIL_INVALID_SIM_STATE"; + case SmsManager.RESULT_RIL_NO_SMS_TO_ACK: + return "RESULT_RIL_NO_SMS_TO_ACK"; + case SmsManager.RESULT_RIL_SIM_BUSY: + return "RESULT_RIL_SIM_BUSY"; + case SmsManager.RESULT_RIL_SIM_FULL: + return "RESULT_RIL_SIM_FULL"; + case SmsManager.RESULT_RIL_NO_SUBSCRIPTION: + return "RESULT_RIL_NO_SUBSCRIPTION"; + case SmsManager.RESULT_RIL_NO_NETWORK_FOUND: + return "RESULT_RIL_NO_NETWORK_FOUND"; + case SmsManager.RESULT_RIL_DEVICE_IN_USE: + return "RESULT_RIL_DEVICE_IN_USE"; + case SmsManager.RESULT_RIL_ABORTED: + return "RESULT_RIL_ABORTED"; + default: + return "NA"; + } + } + } +} diff --git a/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsDatabase.java b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsDatabase.java new file mode 100644 index 0000000000..673eef9612 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsDatabase.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import android.provider.BaseColumns; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; + +/** + * Defines the tables classes which are present in the Telephony Analytics Database, private + * constructor to prevent instantiation. + */ +public final class TelephonyAnalyticsDatabase { + private TelephonyAnalyticsDatabase() {} + + public static final DateTimeFormatter DATE_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.systemDefault()); + + /** + * CallAnalyticsTable class defines the columns in the CallTable Implements the BaseColumns + * class. + */ + public static final class CallAnalyticsTable implements BaseColumns { + public static final String TABLE_NAME = "CallDataLogs"; + public static final String LOG_DATE = "LogDate"; + public static final String CALL_STATUS = "CallStatus"; + public static final String CALL_TYPE = "CallType"; + public static final String RAT = "RAT"; + public static final String SLOT_ID = "SlotID"; + public static final String FAILURE_REASON = "FailureReason"; + public static final String RELEASE_VERSION = "ReleaseVersion"; + public static final String COUNT = "Count"; + } + + /** + * SmsMmsAnalyticsTable class defines the columns in the SmsMmsTable Implements the BaseColumns + * class. + */ + public static final class SmsMmsAnalyticsTable implements BaseColumns { + public static final String TABLE_NAME = "SmsMmsDataLogs"; + public static final String LOG_DATE = "LogDate"; + public static final String SMS_MMS_STATUS = "SmsMmsStatus"; + public static final String SMS_MMS_TYPE = "SmsMmsType"; + public static final String SLOT_ID = "SlotID"; + public static final String RAT = "RAT"; + public static final String FAILURE_REASON = "FailureReason"; + public static final String RELEASE_VERSION = "ReleaseVersion"; + public static final String COUNT = "Count"; + } + + /** + * ServiceStateAnalyticsTable class defines the columns in the ServiceStateTable Implements the + * BaseColumns class. + */ + public static final class ServiceStateAnalyticsTable implements BaseColumns { + public static final String TABLE_NAME = "ServiceStateLogs"; + public static final String LOG_DATE = "LogDate"; + public static final String TIME_DURATION = "TimeDuration"; + public static final String SLOT_ID = "SlotID"; + public static final String RAT = "RAT"; + public static final String DEVICE_STATUS = "DeviceStatus"; + public static final String RELEASE_VERSION = "ReleaseVersion"; + } +} diff --git a/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsProvider.java b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsProvider.java new file mode 100644 index 0000000000..32443cddc0 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import java.util.ArrayList; +/** + * Interface for Telephony Provider Classes + */ +public interface TelephonyAnalyticsProvider { + /** + * Aggregates all information from the db. + * Used when the bugreport is to be pulled. + * @return All the aggregated information in a ArrayList. + */ + ArrayList<String> aggregate(); +} diff --git a/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsUtil.java b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsUtil.java new file mode 100644 index 0000000000..78b607b279 --- /dev/null +++ b/src/java/com/android/internal/telephony/analytics/TelephonyAnalyticsUtil.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.telephony.Rlog; + +import java.util.Calendar; + +/** + * Singleton Utility class to support TelephonyAnalytics Extends SQLiteOpenHelper class. Supports db + * related operations which includes creating tables,insertion,updation,deletion. Supports some + * generic functionality like getting the Cursor resulting from a query. + */ +public class TelephonyAnalyticsUtil extends SQLiteOpenHelper { + private static TelephonyAnalyticsUtil sTelephonyAnalyticsUtil; + private static final String DATABASE_NAME = "telephony_analytics.db"; + private static final int DATABASE_VERSION = 10; + private static final String TAG = TelephonyAnalyticsUtil.class.getSimpleName(); + private static final int MAX_ENTRIES_LIMIT = 1000; + private static final int CUTOFF_MONTHS = 2; + + private TelephonyAnalyticsUtil(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + /** + * Get the instance of the TelephonyAnalyticsUtil class. Instantiates the TelephonyAnalyticsUtil + * object sTelephonyAnalyticsUtil only once. + * + * @return Returns the TelephonyAnalyticsUtil object sTelephonyAnalyticsUtil. + */ + public static synchronized TelephonyAnalyticsUtil getInstance(Context context) { + if (sTelephonyAnalyticsUtil == null) { + sTelephonyAnalyticsUtil = new TelephonyAnalyticsUtil(context); + } + return sTelephonyAnalyticsUtil; + } + + @Override + public void onCreate(SQLiteDatabase db) {} + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} + + /** + * Uses Util class functionality to create CallTable in db + * + * @param createTableQuery : CallTable Schema + */ + @VisibleForTesting + public synchronized void createTable(String createTableQuery) { + try { + SQLiteDatabase db = getWritableDatabase(); + db.execSQL(createTableQuery); + } catch (Exception e) { + Rlog.e(TAG, "Error during table creation : " + e); + } + } + + /** Utility function that performs insertion on the given database table */ + @VisibleForTesting + public synchronized void insert(String tableName, ContentValues values) { + try { + SQLiteDatabase db = getWritableDatabase(); + db.insert(tableName, null, values); + } catch (SQLException e) { + Rlog.e(TAG, "error occurred during insertion"); + } + } + + /** Utility function that performs update query on the given database table */ + @VisibleForTesting + public synchronized int update( + String table, ContentValues values, String whereClause, String[] whereArgs) { + int rowsAffected = -1; + try { + SQLiteDatabase db = getWritableDatabase(); + rowsAffected = db.update(table, values, whereClause, whereArgs); + + } catch (SQLException e) { + Rlog.e(TAG, "Error during update."); + } + return rowsAffected; + } + + /** + * @Return the cursor object obtained from running a query based on given parameters. + */ + @VisibleForTesting + public synchronized Cursor getCursor( + String tableName, + String[] columns, + String selection, + String[] selectionArgs, + String groupBy, + String having, + String orderBy, + String limit) { + + Cursor cursor = null; + try { + SQLiteDatabase db = getReadableDatabase(); + cursor = + db.query( + tableName, + columns, + selection, + selectionArgs, + groupBy, + having, + orderBy, + limit); + } catch (SQLException e) { + Rlog.e(TAG, "Error during querying for getCursor()" + e); + } + return cursor; + } + + /** Returns the count stored in the cursor obtained from query execution. */ + @VisibleForTesting + public synchronized long getCountFromCursor(Cursor cursor) { + long count = 0; + if (cursor != null && cursor.moveToFirst()) { + count = cursor.getInt(0); + } + return count; + } + + /** Deletes Old Data and Overflow data in the db. */ + @VisibleForTesting + public void deleteOverflowAndOldData( + String tableName, String overflowWhereClause, String oldDataWhereClause) { + deleteOverFlowData(tableName, overflowWhereClause); + deleteOldData(tableName, oldDataWhereClause); + } + + protected void deleteOverFlowData(String tableName, String whereClause) { + String[] whereArgs = {Integer.toString(MAX_ENTRIES_LIMIT)}; + delete(tableName, whereClause, whereArgs); + } + + protected void deleteOldData(String tableName, String whereClause) { + String[] whereArgs = {getCutoffDate()}; + delete(tableName, whereClause, whereArgs); + } + + /** Utility function that performs deletion on the database table */ + @VisibleForTesting + public synchronized void delete(String tableName, String whereClause, String[] whereArgs) { + try { + SQLiteDatabase db = getWritableDatabase(); + db.delete(tableName, whereClause, whereArgs); + } catch (SQLException e) { + Rlog.e(TAG, "Sqlite Operation Error during deletion of Overflow data " + e); + } + } + + private String getCutoffDate() { + Calendar cutoffDate = Calendar.getInstance(); + cutoffDate.add(Calendar.MONTH, -1 * CUTOFF_MONTHS); + return DATE_FORMAT.format(cutoffDate.toInstant()); + } +} diff --git a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java index 65f3c4ac13..cb96c67e07 100644 --- a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java +++ b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java @@ -29,6 +29,7 @@ import android.graphics.Bitmap; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.telephony.AnomalyReporter; import android.telephony.SmsMessage; import android.text.TextUtils; @@ -37,6 +38,7 @@ import com.android.internal.telephony.uicc.IccFileHandler; import java.util.Iterator; import java.util.List; +import java.util.UUID; import java.util.Locale; /** * Factory class, used for decoding raw byte arrays, received from baseband, @@ -88,6 +90,11 @@ public class CommandParamsFactory extends Handler { private static final int MAX_GSM7_DEFAULT_CHARS = 239; private static final int MAX_UCS2_CHARS = 118; + // To Report Anomaly + public static final UUID NPE_WHEN_CALLED_SEND_CMD_PARAMS_UUID = + UUID.fromString("c2b85688-516e-11ee-be56-0242ac120002"); + public static final String NPE_WHEN_CALLED_SEND_CMD_PARAMS_ERROR_MSG = + "mCaller[RilMessageDecoder] is Null when called SendCmdParams"; /** * Returns a singleton instance of CommandParamsFactory * @param caller Class used for queuing raw ril messages, decoding them into @@ -306,7 +313,13 @@ public class CommandParamsFactory extends Handler { } private void sendCmdParams(ResultCode resCode) { - mCaller.sendMsgParamsDecoded(resCode, mCmdParams); + if (mCaller != null) { + mCaller.sendMsgParamsDecoded(resCode, mCmdParams); + } else { + CatLog.e(this, "mCaller[RilMessageDecoder] is NULL"); + AnomalyReporter.reportAnomaly(NPE_WHEN_CALLED_SEND_CMD_PARAMS_UUID, + NPE_WHEN_CALLED_SEND_CMD_PARAMS_ERROR_MSG); + } } /** diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index ebc634258b..2119003d14 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -129,6 +129,7 @@ public class CdmaSMSDispatcher extends SMSDispatcher { // if sms over IMS is not supported on data and voice is not available... if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker(tracker); return; } diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 267f70b389..a657ecd8cf 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -41,6 +41,7 @@ import android.telephony.Annotation.NetCapability; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; import android.telephony.data.ApnSetting; +import android.telephony.data.DataServiceCallback; import android.telephony.data.IQualifiedNetworksService; import android.telephony.data.IQualifiedNetworksServiceCallback; import android.telephony.data.QualifiedNetworksService; @@ -51,8 +52,11 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.SparseArray; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.SlidingWindowEventCounter; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.util.FunctionalUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -65,6 +69,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -133,6 +138,8 @@ public class AccessNetworksManager extends Handler { private final @NonNull Set<AccessNetworksManagerCallback> mAccessNetworksManagerCallbacks = new ArraySet<>(); + private final FeatureFlags mFeatureFlags; + /** * Represents qualified network types list on a specific APN type. */ @@ -294,6 +301,43 @@ public class AccessNetworksManager extends Handler { mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList); } } + + /** + * Called when QualifiedNetworksService requests network validation. + * + * Since the data network in the connected state corresponding to the given network + * capability must be validated, a request is tossed to the data network controller. + * @param networkCapability network capability + */ + @Override + public void onNetworkValidationRequested(@NetCapability int networkCapability, + @NonNull IIntegerConsumer resultCodeCallback) { + DataNetworkController dnc = mPhone.getDataNetworkController(); + if (!mFeatureFlags.networkValidation()) { + FunctionalUtils.ignoreRemoteException(resultCodeCallback::accept) + .accept(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + return; + } + + log("onNetworkValidationRequested: networkCapability = [" + + DataUtils.networkCapabilityToString(networkCapability) + "]"); + + dnc.requestNetworkValidation(networkCapability, new Consumer<Integer>() { + @Override + public void accept(Integer result) { + post(() -> { + try { + log("onNetworkValidationRequestDone:" + + DataServiceCallback.resultCodeToString(result)); + resultCodeCallback.accept(result.intValue()); + } catch (RemoteException e) { + // Ignore if the remote process is no longer available to call back. + loge("onNetworkValidationRequestDone RemoteException" + e); + } + }); + } + }); + } } private void onEmergencyDataNetworkPreferredTransportChanged( @@ -337,7 +381,8 @@ public class AccessNetworksManager extends Handler { * @param phone The phone object. * @param looper Looper for the handler. */ - public AccessNetworksManager(@NonNull Phone phone, @NonNull Looper looper) { + public AccessNetworksManager(@NonNull Phone phone, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags) { super(looper); mPhone = phone; mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( @@ -346,6 +391,7 @@ public class AccessNetworksManager extends Handler { mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; + mFeatureFlags = featureFlags; // bindQualifiedNetworksService posts real work to handler thread. So here we can // let the callback execute in binder thread to avoid post twice. diff --git a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java index 87591deebc..e8cd8f017d 100644 --- a/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java +++ b/src/java/com/android/internal/telephony/data/AutoDataSwitchController.java @@ -37,6 +37,7 @@ import android.os.Message; import android.provider.Settings; import android.telephony.AccessNetworkConstants; import android.telephony.NetworkRegistrationInfo; +import android.telephony.NetworkRegistrationInfo.RegistrationState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -46,6 +47,7 @@ import android.util.LocalLog; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.NotificationChannelController; @@ -57,6 +59,8 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; /** * Recommend a data phone to use based on its availability. @@ -102,6 +106,8 @@ public class AutoDataSwitchController extends Handler { private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 4; /** Event indicates the switch state is stable, proceed to validation as the next step. */ private static final int EVENT_MEETS_AUTO_DATA_SWITCH_STATE = 5; + /** Event when subscriptions changed. */ + private static final int EVENT_SUBSCRIPTIONS_CHANGED = 6; /** Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} */ private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; @@ -120,6 +126,7 @@ public class AutoDataSwitchController extends Handler { private final @NonNull LocalLog mLocalLog = new LocalLog(128); private final @NonNull Context mContext; + private final @NonNull FeatureFlags mFlags; private final @NonNull SubscriptionManagerService mSubscriptionManagerService; private final @NonNull PhoneSwitcher mPhoneSwitcher; private final @NonNull AutoDataSwitchControllerCallback mPhoneSwitcherCallback; @@ -133,6 +140,12 @@ public class AutoDataSwitchController extends Handler { */ private long mAutoDataSwitchAvailabilityStabilityTimeThreshold = -1; /** + * The tolerated gap of score for auto data switch decision, larger than which the device will + * switch to the SIM with higher score. If 0, the device will always switch to the higher score + * SIM. If < 0, the network type and signal strength based auto switch is disabled. + */ + private int mScoreTolerance = -1; + /** * {@code true} if requires ping test before switching preferred data modem; otherwise, switch * even if ping test fails. */ @@ -144,36 +157,82 @@ public class AutoDataSwitchController extends Handler { */ private int mAutoDataSwitchValidationMaxRetry; + /** The signal status of phones, where index corresponds to phone Id. */ private @NonNull PhoneSignalStatus[] mPhonesSignalStatus; + /** + * The phone Id of the pending switching phone. Used for pruning frequent switch evaluation. + */ + private int mSelectedTargetPhoneId = INVALID_PHONE_INDEX; /** * To track the signal status of a phone in order to evaluate whether it's a good candidate to * switch to. */ private static class PhoneSignalStatus { - private @NonNull Phone mPhone; - private @NetworkRegistrationInfo.RegistrationState int mDataRegState = - NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; - private @NonNull TelephonyDisplayInfo mDisplayInfo; - private @NonNull SignalStrength mSignalStrength; - - private int mScore; - + /** + * How preferred the current phone is. + */ + enum UsableState { + HOME(1), ROAMING_ENABLED(0), NOT_USABLE(-1); + /** + * The higher the score, the more preferred. + * HOME is preferred over ROAMING assuming roaming is metered. + */ + final int mScore; + UsableState(int score) { + this.mScore = score; + } + } + /** The phone */ + @NonNull private final Phone mPhone; + /** Data registration state of the phone */ + @RegistrationState private int mDataRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + /** Current Telephony display info of the phone */ + @NonNull private TelephonyDisplayInfo mDisplayInfo; + /** Signal strength of the phone */ + @NonNull private SignalStrength mSignalStrength; + /** {@code true} if this slot is listening for events. */ + private boolean mListeningForEvents; private PhoneSignalStatus(@NonNull Phone phone) { this.mPhone = phone; this.mDisplayInfo = phone.getDisplayInfoController().getTelephonyDisplayInfo(); this.mSignalStrength = phone.getSignalStrength(); } - private int updateScore() { - // TODO: score = inservice? dcm.getscore() : 0 - return mScore; + + /** + * @return the current score of this phone. 0 indicates out of service and it will never be + * selected as the secondary data candidate. + */ + private int getRatSignalScore() { + return isInService(mDataRegState) + ? mPhone.getDataNetworkController().getDataConfigManager() + .getAutoDataSwitchScore(mDisplayInfo, mSignalStrength) : 0; + } + + /** + * @return The current usable state of the phone. + */ + private UsableState getUsableState() { + switch (mDataRegState) { + case NetworkRegistrationInfo.REGISTRATION_STATE_HOME: + return UsableState.HOME; + case NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING: + return mPhone.getDataRoamingEnabled() + ? UsableState.ROAMING_ENABLED : UsableState.NOT_USABLE; + default: + return UsableState.NOT_USABLE; + } } + @Override public String toString() { - return "{phoneId=" + mPhone.getPhoneId() - + " score=" + mScore + " dataRegState=" + return "{phone " + mPhone.getPhoneId() + + " score=" + getRatSignalScore() + " dataRegState=" + NetworkRegistrationInfo.registrationStateToString(mDataRegState) + + " " + getUsableState() + " display=" + mDisplayInfo + " signalStrength=" + mSignalStrength.getLevel() + + " listeningForEvents=" + mListeningForEvents + "}"; } @@ -212,16 +271,19 @@ public class AutoDataSwitchController extends Handler { * @param phoneSwitcherCallback Callback for phone switcher to execute. */ public AutoDataSwitchController(@NonNull Context context, @NonNull Looper looper, - @NonNull PhoneSwitcher phoneSwitcher, + @NonNull PhoneSwitcher phoneSwitcher, @NonNull FeatureFlags featureFlags, @NonNull AutoDataSwitchControllerCallback phoneSwitcherCallback) { super(looper); mContext = context; + mFlags = featureFlags; mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mPhoneSwitcher = phoneSwitcher; mPhoneSwitcherCallback = phoneSwitcherCallback; readDeviceResourceConfig(); int numActiveModems = PhoneFactory.getPhones().length; mPhonesSignalStatus = new PhoneSignalStatus[numActiveModems]; + // Listening on all slots on boot up to make sure nothing missed. Later the tracking is + // pruned upon subscriptions changed. for (int phoneId = 0; phoneId < numActiveModems; phoneId++) { registerAllEventsForPhone(phoneId); } @@ -236,16 +298,46 @@ public class AutoDataSwitchController extends Handler { if (oldActiveModems == numActiveModems) return; // Dual -> Single for (int phoneId = numActiveModems; phoneId < oldActiveModems; phoneId++) { - Phone phone = mPhonesSignalStatus[phoneId].mPhone; - phone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this); - phone.getSignalStrengthController().unregisterForSignalStrengthChanged(this); - phone.getServiceStateTracker().unregisterForServiceStateChanged(this); + unregisterAllEventsForPhone(phoneId); } mPhonesSignalStatus = Arrays.copyOf(mPhonesSignalStatus, numActiveModems); // Signal -> Dual for (int phoneId = oldActiveModems; phoneId < numActiveModems; phoneId++) { registerAllEventsForPhone(phoneId); } + logl("onMultiSimConfigChanged: " + Arrays.toString(mPhonesSignalStatus)); + } + + /** Notify subscriptions changed. */ + public void notifySubscriptionsMappingChanged() { + sendEmptyMessage(EVENT_SUBSCRIPTIONS_CHANGED); + } + + /** + * On subscription changed, register/unregister events on phone Id slot that has active/inactive + * sub to reduce unnecessary tracking. + */ + private void onSubscriptionsChanged() { + Set<Integer> activePhoneIds = Arrays.stream(mSubscriptionManagerService + .getActiveSubIdList(true /*visibleOnly*/)) + .map(mSubscriptionManagerService::getPhoneId) + .boxed() + .collect(Collectors.toSet()); + // Track events only if there are at least two active visible subscriptions. + if (activePhoneIds.size() < 2) activePhoneIds.clear(); + boolean changed = false; + for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) { + if (activePhoneIds.contains(phoneId) + && !mPhonesSignalStatus[phoneId].mListeningForEvents) { + registerAllEventsForPhone(phoneId); + changed = true; + } else if (!activePhoneIds.contains(phoneId) + && mPhonesSignalStatus[phoneId].mListeningForEvents) { + unregisterAllEventsForPhone(phoneId); + changed = true; + } + } + if (changed) logl("onSubscriptionChanged: " + Arrays.toString(mPhonesSignalStatus)); } /** @@ -254,7 +346,7 @@ public class AutoDataSwitchController extends Handler { */ private void registerAllEventsForPhone(int phoneId) { Phone phone = PhoneFactory.getPhone(phoneId); - if (phone != null) { + if (phone != null && isActiveModemPhone(phoneId)) { mPhonesSignalStatus[phoneId] = new PhoneSignalStatus(phone); phone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged( this, EVENT_DISPLAY_INFO_CHANGED, phoneId); @@ -262,18 +354,36 @@ public class AutoDataSwitchController extends Handler { this, EVENT_SIGNAL_STRENGTH_CHANGED, phoneId); phone.getServiceStateTracker().registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, phoneId); + mPhonesSignalStatus[phoneId].mListeningForEvents = true; } else { loge("Unexpected null phone " + phoneId + " when register all events"); } } /** + * Unregister all tracking events for a phone. + * @param phoneId The phone to unregister for all events. + */ + private void unregisterAllEventsForPhone(int phoneId) { + if (isActiveModemPhone(phoneId)) { + Phone phone = mPhonesSignalStatus[phoneId].mPhone; + phone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this); + phone.getSignalStrengthController().unregisterForSignalStrengthChanged(this); + phone.getServiceStateTracker().unregisterForServiceStateChanged(this); + mPhonesSignalStatus[phoneId].mListeningForEvents = false; + } else { + loge("Unexpected out of bound phone " + phoneId + " when unregister all events"); + } + } + + /** * Read the default device config from any default phone because the resource config are per * device. No need to register callback for the same reason. */ private void readDeviceResourceConfig() { Phone phone = PhoneFactory.getDefaultPhone(); DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + mScoreTolerance = dataConfig.getAutoDataSwitchScoreTolerance(); mRequirePingTestBeforeSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired(); mAutoDataSwitchAvailabilityStabilityTimeThreshold = dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); @@ -289,24 +399,32 @@ public class AutoDataSwitchController extends Handler { case EVENT_SERVICE_STATE_CHANGED: ar = (AsyncResult) msg.obj; phoneId = (int) ar.userObj; - onRegistrationStateChanged(phoneId); + onServiceStateChanged(phoneId); break; case EVENT_DISPLAY_INFO_CHANGED: ar = (AsyncResult) msg.obj; phoneId = (int) ar.userObj; onDisplayInfoChanged(phoneId); break; + case EVENT_SIGNAL_STRENGTH_CHANGED: + ar = (AsyncResult) msg.obj; + phoneId = (int) ar.userObj; + onSignalStrengthChanged(phoneId); + break; case EVENT_EVALUATE_AUTO_SWITCH: int reason = (int) msg.obj; onEvaluateAutoDataSwitch(reason); break; case EVENT_MEETS_AUTO_DATA_SWITCH_STATE: int targetPhoneId = msg.arg1; - boolean needValidation = (boolean) msg.obj; + boolean needValidation = msg.arg2 == 1; log("require validation on phone " + targetPhoneId + (needValidation ? "" : " no") + " need to pass"); mPhoneSwitcherCallback.onRequireValidation(targetPhoneId, needValidation); break; + case EVENT_SUBSCRIPTIONS_CHANGED: + onSubscriptionsChanged(); + break; default: loge("Unexpected event " + msg.what); } @@ -315,9 +433,9 @@ public class AutoDataSwitchController extends Handler { /** * Called when registration state changed. */ - private void onRegistrationStateChanged(int phoneId) { + private void onServiceStateChanged(int phoneId) { Phone phone = PhoneFactory.getPhone(phoneId); - if (phone != null) { + if (phone != null && isActiveModemPhone(phoneId)) { int oldRegState = mPhonesSignalStatus[phoneId].mDataRegState; int newRegState = phone.getServiceState() .getNetworkRegistrationInfo( @@ -326,44 +444,93 @@ public class AutoDataSwitchController extends Handler { .getRegistrationState(); if (newRegState != oldRegState) { mPhonesSignalStatus[phoneId].mDataRegState = newRegState; - log("onRegistrationStateChanged: phone " + phoneId + " " - + NetworkRegistrationInfo.registrationStateToString(oldRegState) - + " -> " - + NetworkRegistrationInfo.registrationStateToString(newRegState)); - evaluateAutoDataSwitch(EVALUATION_REASON_REGISTRATION_STATE_CHANGED); - } else { - log("onRegistrationStateChanged: no change."); + if (isInService(oldRegState) != isInService(newRegState) + || isHomeService(oldRegState) != isHomeService(newRegState)) { + log("onServiceStateChanged: phone " + phoneId + " " + + NetworkRegistrationInfo.registrationStateToString(oldRegState) + + " -> " + + NetworkRegistrationInfo.registrationStateToString(newRegState)); + evaluateAutoDataSwitch(EVALUATION_REASON_REGISTRATION_STATE_CHANGED); + } } } else { loge("Unexpected null phone " + phoneId + " upon its registration state changed"); } } - /** - * @return {@code true} if the phone state is considered in service. - */ - private boolean isInService(@NetworkRegistrationInfo.RegistrationState int dataRegState) { + /** @return {@code true} if the phone state is considered in service. */ + private static boolean isInService(@RegistrationState int dataRegState) { return dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME || dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; } + /** @return {@code true} if the phone state is in home service. */ + private static boolean isHomeService(@RegistrationState int dataRegState) { + return dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME; + } + /** * Called when {@link TelephonyDisplayInfo} changed. This can happen when network types or * override network types (5G NSA, 5G MMWAVE) change. + * @param phoneId The phone that changed. */ private void onDisplayInfoChanged(int phoneId) { Phone phone = PhoneFactory.getPhone(phoneId); - if (phone != null) { + if (phone != null && isActiveModemPhone(phoneId)) { TelephonyDisplayInfo displayInfo = phone.getDisplayInfoController() .getTelephonyDisplayInfo(); - //TODO(b/260928808) - log("onDisplayInfoChanged:" + displayInfo); + mPhonesSignalStatus[phoneId].mDisplayInfo = displayInfo; + if (getHigherScoreCandidatePhoneId() != mSelectedTargetPhoneId) { + log("onDisplayInfoChanged: phone " + phoneId + " " + displayInfo); + evaluateAutoDataSwitch(EVALUATION_REASON_DISPLAY_INFO_CHANGED); + } } else { loge("Unexpected null phone " + phoneId + " upon its display info changed"); } } /** + * Called when {@link SignalStrength} changed. + * @param phoneId The phone that changed. + */ + private void onSignalStrengthChanged(int phoneId) { + Phone phone = PhoneFactory.getPhone(phoneId); + if (phone != null && isActiveModemPhone(phoneId)) { + SignalStrength newSignalStrength = phone.getSignalStrength(); + SignalStrength oldSignalStrength = mPhonesSignalStatus[phoneId].mSignalStrength; + if (oldSignalStrength.getLevel() != newSignalStrength.getLevel()) { + mPhonesSignalStatus[phoneId].mSignalStrength = newSignalStrength; + if (getHigherScoreCandidatePhoneId() != mSelectedTargetPhoneId) { + log("onSignalStrengthChanged: phone " + phoneId + " " + + oldSignalStrength.getLevel() + "->" + newSignalStrength.getLevel()); + evaluateAutoDataSwitch(EVALUATION_REASON_SIGNAL_STRENGTH_CHANGED); + } + } + } else { + loge("Unexpected null phone " + phoneId + " upon its signal strength changed"); + } + } + + /** + * Called as a preliminary check for the frequent signal/display info change. + * @return The phone Id if found a candidate phone with higher signal score. + */ + private int getHigherScoreCandidatePhoneId() { + int preferredPhoneId = mPhoneSwitcher.getPreferredDataPhoneId(); + if (isActiveModemPhone(preferredPhoneId)) { + int currentScore = mPhonesSignalStatus[preferredPhoneId].getRatSignalScore(); + for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) { + int candidateScore = mPhonesSignalStatus[phoneId].getRatSignalScore(); + if (phoneId != preferredPhoneId + && (candidateScore - currentScore) > mScoreTolerance) { + return phoneId; + } + } + } + return INVALID_PHONE_INDEX; + } + + /** * Schedule for auto data switch evaluation. * @param reason The reason for the evaluation. */ @@ -388,10 +555,7 @@ public class AutoDataSwitchController extends Handler { if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return; int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); // check is valid DSDS - if (!isActiveSubId(defaultDataSubId) || mSubscriptionManagerService - .getActiveSubIdList(true).length <= 1) { - return; - } + if (mSubscriptionManagerService.getActiveSubIdList(true).length < 2) return; Phone defaultDataPhone = PhoneFactory.getPhone(mSubscriptionManagerService.getPhoneId( defaultDataSubId)); if (defaultDataPhone == null) { @@ -401,13 +565,16 @@ public class AutoDataSwitchController extends Handler { } int defaultDataPhoneId = defaultDataPhone.getPhoneId(); int preferredPhoneId = mPhoneSwitcher.getPreferredDataPhoneId(); - log("onEvaluateAutoDataSwitch: defaultPhoneId: " + defaultDataPhoneId - + " preferredPhoneId: " + preferredPhoneId - + " reason: " + evaluationReasonToString(reason)); + StringBuilder debugMessage = new StringBuilder("onEvaluateAutoDataSwitch:"); + debugMessage.append(" defaultPhoneId: ").append(defaultDataPhoneId) + .append(" preferredPhoneId: ").append(preferredPhoneId) + .append(", reason: ").append(evaluationReasonToString(reason)); if (preferredPhoneId == defaultDataPhoneId) { // on default data sub - int candidatePhoneId = getSwitchCandidatePhoneId(defaultDataPhoneId); + int candidatePhoneId = getSwitchCandidatePhoneId(defaultDataPhoneId, debugMessage); + log(debugMessage.toString()); if (candidatePhoneId != INVALID_PHONE_INDEX) { + mSelectedTargetPhoneId = candidatePhoneId; startStabilityCheck(candidatePhoneId, mRequirePingTestBeforeSwitch); } else { cancelAnyPendingSwitch(); @@ -415,90 +582,239 @@ public class AutoDataSwitchController extends Handler { } else { // on backup data sub Phone backupDataPhone = PhoneFactory.getPhone(preferredPhoneId); - if (backupDataPhone == null) { - loge("onEvaluateAutoDataSwitch: Unexpected null phone " + preferredPhoneId - + " as the current active data phone"); + if (backupDataPhone == null || !isActiveModemPhone(preferredPhoneId)) { + loge(debugMessage.append(" Unexpected null phone ").append(preferredPhoneId) + .append(" as the current active data phone").toString()); return; } if (!defaultDataPhone.isUserDataEnabled() || !backupDataPhone.isDataAllowed()) { - // immediately switch back if user disabled setting changes mPhoneSwitcherCallback.onRequireImmediatelySwitchToPhone(DEFAULT_PHONE_INDEX, EVALUATION_REASON_DATA_SETTINGS_CHANGED); + log(debugMessage.append(", immediately back to default as user turns off settings") + .toString()); return; } - if (mDefaultNetworkIsOnNonCellular) { - log("onEvaluateAutoDataSwitch: Default network is active on nonCellular transport"); - startStabilityCheck(DEFAULT_PHONE_INDEX, false); - return; - } + boolean backToDefault = false; + boolean needValidation = true; - if (mPhonesSignalStatus[preferredPhoneId].mDataRegState - != NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { - // backup phone lost its HOME registration - startStabilityCheck(DEFAULT_PHONE_INDEX, false); - return; - } + if (mFlags.autoSwitchAllowRoaming()) { + if (mDefaultNetworkIsOnNonCellular) { + debugMessage.append(", back to default as default network") + .append(" is active on nonCellular transport"); + backToDefault = true; + needValidation = false; + } else { + PhoneSignalStatus.UsableState defaultUsableState = + mPhonesSignalStatus[defaultDataPhoneId].getUsableState(); + PhoneSignalStatus.UsableState currentUsableState = + mPhonesSignalStatus[preferredPhoneId].getUsableState(); - if (isInService(mPhonesSignalStatus[defaultDataPhoneId].mDataRegState)) { - // default phone is back to service - startStabilityCheck(DEFAULT_PHONE_INDEX, mRequirePingTestBeforeSwitch); - return; + boolean isCurrentUsable = currentUsableState.mScore + > PhoneSignalStatus.UsableState.NOT_USABLE.mScore; + + if (currentUsableState.mScore < defaultUsableState.mScore) { + debugMessage.append(", back to default phone ").append(preferredPhoneId) + .append(" : ").append(defaultUsableState) + .append(" , backup phone: ").append(currentUsableState); + + backToDefault = true; + // Require validation if the current preferred phone is usable. + needValidation = isCurrentUsable && mRequirePingTestBeforeSwitch; + } else if (defaultUsableState.mScore == currentUsableState.mScore) { + debugMessage.append(", default phone ").append(preferredPhoneId) + .append(" : ").append(defaultUsableState) + .append(" , backup phone: ").append(currentUsableState); + + if (isCurrentUsable) { + // Both phones are usable. + if (isRatSignalStrengthBasedSwitchEnabled()) { + int defaultScore = mPhonesSignalStatus[defaultDataPhoneId] + .getRatSignalScore(); + int currentScore = mPhonesSignalStatus[preferredPhoneId] + .getRatSignalScore(); + if ((defaultScore - currentScore) > mScoreTolerance) { + debugMessage + .append(", back to default for higher score ") + .append(defaultScore).append(" versus current ") + .append(currentScore); + backToDefault = true; + needValidation = mRequirePingTestBeforeSwitch; + } + } else { + // Only OOS/in service switch is enabled, switch back. + debugMessage.append(", back to default as it's usable. "); + backToDefault = true; + needValidation = mRequirePingTestBeforeSwitch; + } + } else { + debugMessage.append(", back to default as both phones are unusable."); + backToDefault = true; + needValidation = false; + } + } + } + } else { + if (mDefaultNetworkIsOnNonCellular) { + debugMessage.append(", back to default as default network") + .append(" is active on nonCellular transport"); + backToDefault = true; + needValidation = false; + } else if (!isHomeService(mPhonesSignalStatus[preferredPhoneId].mDataRegState)) { + debugMessage.append(", back to default as backup phone lost HOME registration"); + backToDefault = true; + needValidation = false; + } else if (isRatSignalStrengthBasedSwitchEnabled()) { + int defaultScore = mPhonesSignalStatus[defaultDataPhoneId].getRatSignalScore(); + int currentScore = mPhonesSignalStatus[preferredPhoneId].getRatSignalScore(); + if ((defaultScore - currentScore) > mScoreTolerance) { + debugMessage + .append(", back to default as default phone has higher score ") + .append(defaultScore).append(" versus current ") + .append(currentScore); + backToDefault = true; + needValidation = mRequirePingTestBeforeSwitch; + } + } else if (isInService(mPhonesSignalStatus[defaultDataPhoneId].mDataRegState)) { + debugMessage.append(", back to default as the default is back to service "); + backToDefault = true; + needValidation = mRequirePingTestBeforeSwitch; + } } - // cancel any previous attempts of switching back to default phone - cancelAnyPendingSwitch(); + if (backToDefault) { + log(debugMessage.toString()); + mSelectedTargetPhoneId = defaultDataPhoneId; + startStabilityCheck(DEFAULT_PHONE_INDEX, needValidation); + } else { + // cancel any previous attempts of switching back to default phone + cancelAnyPendingSwitch(); + } } } /** * Called when consider switching from primary default data sub to another data sub. + * @param defaultPhoneId The default data phone + * @param debugMessage Debug message. * @return the target subId if a suitable candidate is found, otherwise return * {@link SubscriptionManager#INVALID_PHONE_INDEX} */ - private int getSwitchCandidatePhoneId(int defaultPhoneId) { + private int getSwitchCandidatePhoneId(int defaultPhoneId, @NonNull StringBuilder debugMessage) { Phone defaultDataPhone = PhoneFactory.getPhone(defaultPhoneId); if (defaultDataPhone == null) { - log("getSwitchCandidatePhoneId: no sim loaded"); + debugMessage.append(", no candidate as no sim loaded"); return INVALID_PHONE_INDEX; } if (!defaultDataPhone.isUserDataEnabled()) { - log("getSwitchCandidatePhoneId: user disabled data"); + debugMessage.append(", no candidate as user disabled mobile data"); return INVALID_PHONE_INDEX; } if (mDefaultNetworkIsOnNonCellular) { - // Exists other active default transport - log("getSwitchCandidatePhoneId: Default network is active on non-cellular transport"); + debugMessage.append(", no candidate as default network is active") + .append(" on non-cellular transport"); return INVALID_PHONE_INDEX; } - // check whether primary and secondary signal status are worth switching - if (isInService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) { - log("getSwitchCandidatePhoneId: DDS is in service"); - return INVALID_PHONE_INDEX; + if (mFlags.autoSwitchAllowRoaming()) { + // check whether primary and secondary signal status are worth switching + if (!isRatSignalStrengthBasedSwitchEnabled() + && isHomeService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) { + debugMessage.append(", no candidate as default phone is in HOME service"); + return INVALID_PHONE_INDEX; + } + } else { + // check whether primary and secondary signal status are worth switching + if (!isRatSignalStrengthBasedSwitchEnabled() + && isInService(mPhonesSignalStatus[defaultPhoneId].mDataRegState)) { + debugMessage.append(", no candidate as default phone is in service"); + return INVALID_PHONE_INDEX; + } } + + PhoneSignalStatus defaultPhoneStatus = mPhonesSignalStatus[defaultPhoneId]; for (int phoneId = 0; phoneId < mPhonesSignalStatus.length; phoneId++) { - if (phoneId != defaultPhoneId) { + if (phoneId == defaultPhoneId) continue; + + Phone secondaryDataPhone = null; + PhoneSignalStatus candidatePhoneStatus = mPhonesSignalStatus[phoneId]; + if (mFlags.autoSwitchAllowRoaming()) { + PhoneSignalStatus.UsableState currentUsableState = + mPhonesSignalStatus[defaultPhoneId].getUsableState(); + PhoneSignalStatus.UsableState candidatePhoneUsableRank = + mPhonesSignalStatus[phoneId].getUsableState(); + debugMessage.append(", found phone ").append(phoneId).append(" is ").append( + candidatePhoneUsableRank) + .append(", current is ").append(currentUsableState); + if (candidatePhoneUsableRank.mScore > currentUsableState.mScore) { + secondaryDataPhone = PhoneFactory.getPhone(phoneId); + } else if (isRatSignalStrengthBasedSwitchEnabled() + && currentUsableState.mScore == candidatePhoneUsableRank.mScore) { + // Both phones are home or both roaming enabled, so compare RAT/signal score. + + int defaultScore = defaultPhoneStatus.getRatSignalScore(); + int candidateScore = candidatePhoneStatus.getRatSignalScore(); + if ((candidateScore - defaultScore) > mScoreTolerance) { + debugMessage.append(" with higher score ").append( + candidateScore) + .append(" versus current ").append(defaultScore); + secondaryDataPhone = PhoneFactory.getPhone(phoneId); + } else { + debugMessage.append(", but its score ").append(candidateScore) + .append(" doesn't meet the bar to switch given the current ") + .append(defaultScore); + } + } + } else if (isHomeService(candidatePhoneStatus.mDataRegState)) { // the alternative phone must have HOME availability - if (mPhonesSignalStatus[phoneId].mDataRegState - == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { - log("getSwitchCandidatePhoneId: found phone " + phoneId - + " in HOME service"); - Phone secondaryDataPhone = PhoneFactory.getPhone(phoneId); - if (secondaryDataPhone != null && // check auto switch feature enabled - secondaryDataPhone.isDataAllowed()) { - return phoneId; + debugMessage.append(", found phone ").append(phoneId).append(" in HOME service"); + + if (isInService(defaultPhoneStatus.mDataRegState)) { + // Use score if RAT/signal strength based switch is enabled and both phone are + // in service. + if (isRatSignalStrengthBasedSwitchEnabled()) { + int defaultScore = mPhonesSignalStatus[defaultPhoneId].getRatSignalScore(); + int candidateScore = mPhonesSignalStatus[phoneId].getRatSignalScore(); + if ((candidateScore - defaultScore) > mScoreTolerance) { + debugMessage.append(" with higher score ").append(candidateScore) + .append(" versus current ").append(defaultScore); + secondaryDataPhone = PhoneFactory.getPhone(phoneId); + } else { + debugMessage.append(", but its score ").append(candidateScore) + .append(" doesn't meet the bar to switch given the current ") + .append(defaultScore); + } } + } else { + // Only OOS/in service switch is enabled. + secondaryDataPhone = PhoneFactory.getPhone(phoneId); + } + } + + if (secondaryDataPhone != null) { + // check auto switch feature enabled + if (secondaryDataPhone.isDataAllowed()) { + return phoneId; + } else { + debugMessage.append(", but its data is not allowed"); } } } + debugMessage.append(", found no qualified candidate."); return INVALID_PHONE_INDEX; } /** + * @return {@code true} If the feature of switching base on RAT and signal strength is enabled. + */ + private boolean isRatSignalStrengthBasedSwitchEnabled() { + return mFlags.autoDataSwitchRatSs() && mScoreTolerance >= 0; + } + + /** * Called when the current environment suits auto data switch. * Start pre-switch validation if the current environment suits auto data switch for * {@link #mAutoDataSwitchAvailabilityStabilityTimeThreshold} MS. @@ -508,10 +824,12 @@ public class AutoDataSwitchController extends Handler { private void startStabilityCheck(int targetPhoneId, boolean needValidation) { log("startAutoDataSwitchStabilityCheck: targetPhoneId=" + targetPhoneId + " needValidation=" + needValidation); - if (!hasMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE, needValidation)) { + String combinationIdentifier = targetPhoneId + "" + needValidation; + if (!hasEqualMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE, combinationIdentifier)) { + removeMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE); sendMessageDelayed(obtainMessage(EVENT_MEETS_AUTO_DATA_SWITCH_STATE, targetPhoneId, - 0/*placeholder*/, - needValidation), + needValidation ? 1 : 0, + combinationIdentifier), mAutoDataSwitchAvailabilityStabilityTimeThreshold); } } @@ -566,6 +884,7 @@ public class AutoDataSwitchController extends Handler { * Cancel any auto switch attempts when the current environment is not suitable for auto switch. */ private void cancelAnyPendingSwitch() { + mSelectedTargetPhoneId = INVALID_PHONE_INDEX; resetFailedCount(); removeMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE); mPhoneSwitcherCallback.onRequireCancelAnyPendingAutoSwitchValidation(); @@ -651,6 +970,14 @@ public class AutoDataSwitchController extends Handler { } /** + * @param phoneId The phone Id to check. + * @return {@code true} if the phone Id is an active modem. + */ + private boolean isActiveModemPhone(int phoneId) { + return phoneId >= 0 && phoneId < mPhonesSignalStatus.length; + } + + /** * Log debug messages. * @param s debug messages */ @@ -686,11 +1013,13 @@ public class AutoDataSwitchController extends Handler { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("AutoDataSwitchController:"); pw.increaseIndent(); + pw.println("mScoreTolerance=" + mScoreTolerance); pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry + " mAutoSwitchValidationFailedCount=" + mAutoSwitchValidationFailedCount); pw.println("mRequirePingTestBeforeDataSwitch=" + mRequirePingTestBeforeSwitch); pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + mAutoDataSwitchAvailabilityStabilityTimeThreshold); + pw.println("mSelectedTargetPhoneId=" + mSelectedTargetPhoneId); pw.increaseIndent(); for (PhoneSignalStatus status: mPhonesSignalStatus) { pw.println(status); diff --git a/src/java/com/android/internal/telephony/data/CellularDataService.java b/src/java/com/android/internal/telephony/data/CellularDataService.java index c5923aae01..80d6b531b9 100644 --- a/src/java/com/android/internal/telephony/data/CellularDataService.java +++ b/src/java/com/android/internal/telephony/data/CellularDataService.java @@ -167,6 +167,7 @@ public class CellularDataService extends DataService { boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, DataServiceCallback callback) { + // TODO: remove isRoaming parameter if (DBG) log("setupDataCall " + getSlotIndex()); Message message = null; @@ -177,9 +178,9 @@ public class CellularDataService extends DataService { mCallbackMap.put(message, callback); } - mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, - reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor, - matchAllRuleAllowed, message); + mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, allowRoaming, reason, + linkProperties, pduSessionId, sliceInfo, trafficDescriptor, matchAllRuleAllowed, + message); } @Override @@ -199,7 +200,8 @@ public class CellularDataService extends DataService { @Override public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, - DataServiceCallback callback) { + DataServiceCallback callback) { + // TODO: remove isRoaming parameter if (DBG) log("setInitialAttachApn " + getSlotIndex()); Message message = null; @@ -210,12 +212,13 @@ public class CellularDataService extends DataService { mCallbackMap.put(message, callback); } - mPhone.mCi.setInitialAttachApn(dataProfile, isRoaming, message); + mPhone.mCi.setInitialAttachApn(dataProfile, message); } @Override public void setDataProfile(List<DataProfile> dps, boolean isRoaming, - DataServiceCallback callback) { + DataServiceCallback callback) { + // TODO: remove isRoaming parameter if (DBG) log("setDataProfile " + getSlotIndex()); Message message = null; @@ -226,7 +229,7 @@ public class CellularDataService extends DataService { mCallbackMap.put(message, callback); } - mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), isRoaming, message); + mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), message); } @Override diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index f7fe4ad0f8..ea7b1da2a8 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -31,6 +31,7 @@ import android.telephony.Annotation.ApnType; import android.telephony.Annotation.NetCapability; import android.telephony.Annotation.NetworkType; import android.telephony.CarrierConfigManager; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; @@ -46,6 +47,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.DataNetworkController.HandoverRule; import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryRule; import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryRule; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -213,8 +215,8 @@ public class DataConfigManager extends Handler { "anomaly_network_handover_timeout"; /** DeviceConfig key of anomaly report: True for enabling APN config invalidity detection */ private static final String KEY_ANOMALY_APN_CONFIG_ENABLED = "anomaly_apn_config_enabled"; - /** Invalid auto data switch score. */ - private static final int INVALID_AUTO_DATA_SWITCH_SCORE = -1; + /** Placeholder indicating missing Auto data switch score config, meaning out of service. */ + private static final int OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE = 0; /** Anomaly report thresholds for frequent setup data call failure. */ private EventFrequency mSetupDataCallAnomalyReportThreshold; @@ -259,6 +261,7 @@ public class DataConfigManager extends Handler { private @NonNull final Phone mPhone; private @NonNull final String mLogTag; + @NonNull private final FeatureFlags mFeatureFlags; private @NonNull final CarrierConfigManager mCarrierConfigManager; private @NonNull PersistableBundle mCarrierConfig = null; private @NonNull Resources mResources = null; @@ -295,6 +298,9 @@ public class DataConfigManager extends Handler { private @NonNull final List<HandoverRule> mHandoverRuleList = new ArrayList<>(); /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ private boolean mShouldKeepNetworkUpInNonVops = false; + /** The set of network types that enable VOPS even in non VOPS area. */ + @NonNull private final @CarrierConfigManager.Ims.NetworkType List<Integer> + mEnabledVopsNetworkTypesInNonVops = new ArrayList<>(); /** * A map of network types to the estimated downlink values by signal strength 0 - 4 for that * network type @@ -309,9 +315,11 @@ public class DataConfigManager extends Handler { * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. */ - public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper) { + public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags) { super(looper); mPhone = phone; + mFeatureFlags = featureFlags; mLogTag = "DCM-" + mPhone.getPhoneId(); log("DataConfigManager created."); @@ -326,7 +334,7 @@ public class DataConfigManager extends Handler { // Register for device config update DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_TELEPHONY, this::post, + DeviceConfig.NAMESPACE_TELEPHONY, Runnable::run, properties -> { if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, properties.getNamespace())) { @@ -590,10 +598,20 @@ public class DataConfigManager extends Handler { */ public @NonNull @NetCapability Set<Integer> getMeteredNetworkCapabilities(boolean isRoaming) { Set<Integer> meteredApnTypes = isRoaming ? mRoamingMeteredApnTypes : mMeteredApnTypes; - return meteredApnTypes.stream() + Set<Integer> meteredCapabilities = meteredApnTypes.stream() .map(DataUtils::apnTypeToNetworkCapability) .filter(cap -> cap >= 0) - .collect(Collectors.toUnmodifiableSet()); + .collect(Collectors.toSet()); + + // Consumer slices are the slices that are allowed to be accessed by regular application to + // get better performance. They should be metered. This can be turned into configurations in + // the future. + if (mFeatureFlags.meteredEmbbUrlcc()) { + meteredCapabilities.add(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH); + meteredCapabilities.add(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY); + } + + return Collections.unmodifiableSet(meteredCapabilities); } /** @@ -666,6 +684,11 @@ public class DataConfigManager extends Handler { synchronized (this) { mShouldKeepNetworkUpInNonVops = mCarrierConfig.getBoolean(CarrierConfigManager .Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL); + int[] allowedNetworkTypes = mCarrierConfig.getIntArray( + CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY); + if (allowedNetworkTypes != null) { + Arrays.stream(allowedNetworkTypes).forEach(mEnabledVopsNetworkTypesInNonVops::add); + } } } @@ -684,9 +707,29 @@ public class DataConfigManager extends Handler { return Collections.unmodifiableSet(mCapabilitiesExemptFromSingleDataList); } - /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ - public boolean shouldKeepNetworkUpInNonVops() { - return mShouldKeepNetworkUpInNonVops; + /** + * @param regState The modem reported data registration state. + * @return {@code true} if should keep IMS network in case of moving to non VOPS area. + */ + public boolean shouldKeepNetworkUpInNonVops(@NetworkRegistrationInfo.RegistrationState + int regState) { + return mShouldKeepNetworkUpInNonVops || allowBringUpNetworkInNonVops(regState); + } + + /** + * @param regState The modem reported data registration state. + * @return {@code true} if allow bring up IMS network in case of moving to non VOPS area. + */ + public boolean allowBringUpNetworkInNonVops(@NetworkRegistrationInfo.RegistrationState + int regState) { + if (!mFeatureFlags.allowMmtelInNonVops()) return false; + int networkType = -1; + if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + networkType = CarrierConfigManager.Ims.NETWORK_TYPE_HOME; + } else if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) { + networkType = CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING; + } + return mEnabledVopsNetworkTypesInNonVops.contains(networkType); } /** {@code True} requires ping test to pass on the target slot before switching to it.*/ @@ -941,6 +984,7 @@ public class DataConfigManager extends Handler { DATA_CONFIG_NETWORK_TYPE_EHRPD, DATA_CONFIG_NETWORK_TYPE_IDEN, DATA_CONFIG_NETWORK_TYPE_LTE, + DATA_CONFIG_NETWORK_TYPE_LTE_CA, DATA_CONFIG_NETWORK_TYPE_HSPAP, DATA_CONFIG_NETWORK_TYPE_GSM, DATA_CONFIG_NETWORK_TYPE_TD_SCDMA, @@ -978,12 +1022,14 @@ public class DataConfigManager extends Handler { * @param displayInfo The displayed network info. * @param signalStrength The signal strength. * @return Score base on network type and signal strength to inform auto data switch decision. + * The min score is {@link #OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE} indicating missing config. */ public int getAutoDataSwitchScore(@NonNull TelephonyDisplayInfo displayInfo, @NonNull SignalStrength signalStrength) { int[] scores = mAutoDataSwitchNetworkTypeSignalMap.get( getDataConfigNetworkType(displayInfo)); - return scores != null ? scores[signalStrength.getLevel()] : INVALID_AUTO_DATA_SWITCH_SCORE; + return scores != null ? scores[signalStrength.getLevel()] + : OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE; } /** @@ -1421,7 +1467,8 @@ public class DataConfigManager extends Handler { pw.println("Capabilities exempt from single PDN=" + mCapabilitiesExemptFromSingleDataList .stream().map(DataUtils::networkCapabilityToString) .collect(Collectors.joining(","))); - pw.println("mShouldKeepNetworkUpInNoVops=" + mShouldKeepNetworkUpInNonVops); + pw.println("mShouldKeepNetworkUpInNonVops=" + mShouldKeepNetworkUpInNonVops); + pw.println("mEnabledVopsNetworkTypesInNonVops=" + mEnabledVopsNetworkTypesInNonVops); pw.println("isPingTestBeforeAutoDataSwitchRequired=" + isPingTestBeforeAutoDataSwitchRequired()); pw.println("Unmetered network types=" + String.join(",", mUnmeteredNetworkTypes)); diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java index 2ba3fe46ea..6858c6a032 100644 --- a/src/java/com/android/internal/telephony/data/DataEvaluation.java +++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java @@ -155,6 +155,21 @@ public class DataEvaluation { } /** + * Check if all the disallowed reasons are a subset of the given reason. + * + * @param reasons The given reason to check + * @return {@code true} if it doesn't contain any disallowed reasons other than the given + * reasons. + */ + public boolean isSubsetOf(DataDisallowedReason... reasons) { + int matched = 0; + for (DataDisallowedReason requestedReason : reasons) { + if (mDataDisallowedReasons.contains(requestedReason)) matched++; + } + return matched == mDataDisallowedReasons.size(); + } + + /** * Check if the any of the disallowed reasons match one of the provided reason. * * @param reasons The given reasons to check. @@ -290,6 +305,8 @@ public class DataEvaluation { SIM_NOT_READY(true), /** Concurrent voice and data is not allowed. */ CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), + /** Service option not supported. */ + SERVICE_OPTION_NOT_SUPPORTED(true), /** Carrier notified data should be restricted. */ DATA_RESTRICTED_BY_NETWORK(true), /** Radio power is off (i.e. airplane mode on) */ diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 6ba251b430..bba0f19bf9 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -74,6 +74,7 @@ import android.telephony.data.DataProfile; import android.telephony.data.DataService; import android.telephony.data.DataServiceCallback; import android.telephony.data.NetworkSliceInfo; +import android.telephony.data.Qos; import android.telephony.data.QosBearerSession; import android.telephony.data.TrafficDescriptor; import android.telephony.data.TrafficDescriptor.OsAppId; @@ -95,11 +96,14 @@ import com.android.internal.telephony.data.DataEvaluation.DataAllowedReason; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryEntry; import com.android.internal.telephony.data.DataRetryManager.DataRetryEntry; +import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; import com.android.internal.telephony.data.TelephonyNetworkAgent.TelephonyNetworkAgentCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.metrics.DataCallSessionStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FunctionalUtils; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -253,6 +257,12 @@ public class DataNetwork extends StateMachine { */ private static final int EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE = 27; + /** Event for data network validation request from the AccessNetworksManager. */ + private static final int EVENT_DATA_NETWORK_VALIDATION_REQUESTED = 28; + + /** Event for response to data network validation request. */ + private static final int EVENT_DATA_NETWORK_VALIDATION_RESPONSE = 29; + /** Invalid context id. */ private static final int INVALID_CID = -1; @@ -278,6 +288,7 @@ public class DataNetwork extends StateMachine { TEAR_DOWN_REASON_RAT_NOT_ALLOWED, TEAR_DOWN_REASON_ROAMING_DISABLED, TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED, + TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED, TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY, TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER, TEAR_DOWN_REASON_DATA_STALL, @@ -329,7 +340,8 @@ public class DataNetwork extends StateMachine { /** Data network tear down due to concurrent voice/data not allowed. */ public static final int TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED = 8; - + /** Data network tear down due to service option is not supported. */ + public static final int TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED = 9; /** Data network tear down due to data service unbound. */ public static final int TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY = 10; @@ -394,6 +406,10 @@ public class DataNetwork extends StateMachine { /** Data network tear down due to preferred data switched to another phone. */ public static final int TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED = 30; + //********************************************************************************************// + // WHENEVER ADD A NEW TEAR DOWN REASON, PLEASE UPDATE DataDeactivateReasonEnum in enums.proto // + //********************************************************************************************// + @IntDef(prefix = {"BANDWIDTH_SOURCE_"}, value = { BANDWIDTH_SOURCE_UNKNOWN, @@ -436,9 +452,9 @@ public class DataNetwork extends StateMachine { // Connectivity service will support NOT_METERED as a mutable and requestable // capability. NetworkCapabilities.NET_CAPABILITY_NOT_METERED, - // Even though MMTEL is an immutable capability, we still make it an mutable capability - // here before we have a better solution to deal with network transition from VoPS - // to non-VoPS network. + // Dynamically add and remove MMTEL capability when network transition between VoPS + // and non-VoPS network if the request is not MMTEL. For MMTEL, we retain the capability + // to prevent immediate tear down. NetworkCapabilities.NET_CAPABILITY_MMTEL ); @@ -486,6 +502,9 @@ public class DataNetwork extends StateMachine { /** The phone instance. */ private final @NonNull Phone mPhone; + /** Feature flags */ + private final @NonNull FeatureFlags mFlags; + /** * The subscription id. This is assigned when the network is created, and not supposed to * change afterwards. @@ -493,7 +512,7 @@ public class DataNetwork extends StateMachine { private final int mSubId; /** The network score of this network. */ - private int mNetworkScore; + private @NonNull NetworkScore mNetworkScore; /** * Indicates that @@ -556,6 +575,9 @@ public class DataNetwork extends StateMachine { private final @NonNull DataNetworkController.DataNetworkControllerCallback mDataNetworkControllerCallback; + /** Data settings manager callback. */ + private @NonNull DataSettingsManagerCallback mDataSettingsManagerCallback; + /** Data config manager. */ private final @NonNull DataConfigManager mDataConfigManager; @@ -681,6 +703,9 @@ public class DataNetwork extends StateMachine { /** The QOS bearer sessions. */ private final @NonNull List<QosBearerSession> mQosBearerSessions = new ArrayList<>(); + /** The QOS for the Default Bearer, should be non-null on LTE and NR */ + private @Nullable Qos mDefaultQos; + /** * The UIDs of packages that have carrier privilege. */ @@ -705,6 +730,19 @@ public class DataNetwork extends StateMachine { private @Nullable DataConfigManagerCallback mDataConfigManagerCallback; /** + * Network validation status for this data network. If the data service provider does not + * support the network validation feature, should be UNSUPPORTED. + */ + private @PreciseDataConnectionState.NetworkValidationStatus int mNetworkValidationStatus = + PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED; + + /** + * Callback used to respond to a network validation request to determine whether the request is + * successfully submitted. If the request has been submitted, change it to null. + */ + private @Nullable Consumer<Integer> mNetworkValidationResultCodeCallback; + + /** * The network bandwidth. */ public static class NetworkBandwidth { @@ -887,7 +925,7 @@ public class DataNetwork extends StateMachine { * @param dataAllowedReason The reason that why setting up this data network is allowed. * @param callback The callback to receives data network state update. */ - public DataNetwork(@NonNull Phone phone, @NonNull Looper looper, + public DataNetwork(@NonNull Phone phone, FeatureFlags featureFlags, @NonNull Looper looper, @NonNull SparseArray<DataServiceManager> dataServiceManagers, @NonNull DataProfile dataProfile, @NonNull NetworkRequestList networkRequestList, @@ -901,6 +939,7 @@ public class DataNetwork extends StateMachine { initializeStateMachine(); mPhone = phone; + mFlags = featureFlags; mSubId = phone.getSubId(); mRil = mPhone.mCi; mLinkProperties = new LinkProperties(); @@ -1024,10 +1063,18 @@ public class DataNetwork extends StateMachine { mPhone.getPhoneId()); final NetworkProvider provider = (null == factory) ? null : factory.getProvider(); - mNetworkScore = getNetworkScore(); + // Always prefer IWLAN network for MMS designated network. + // TODO(b/293656884) Proper use of primary transport to avoid conflicting with DSDA. + boolean isPreferred = mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN + && getApnTypeNetworkCapability() == NetworkCapabilities.NET_CAPABILITY_MMS; + + mNetworkScore = new NetworkScore.Builder().setTransportPrimary(isPreferred) + .setKeepConnectedReason(isHandoverInProgress() + ? NetworkScore.KEEP_CONNECTED_FOR_HANDOVER + : NetworkScore.KEEP_CONNECTED_NONE).build(); + return new TelephonyNetworkAgent(mPhone, getHandler().getLooper(), this, - new NetworkScore.Builder().setLegacyInt(mNetworkScore).build(), - configBuilder.build(), provider, + mNetworkScore, configBuilder.build(), provider, new TelephonyNetworkAgentCallback(getHandler()::post) { @Override public void onValidationStatus(@ValidationStatus int status, @@ -1058,6 +1105,34 @@ public class DataNetwork extends StateMachine { mRil.registerForPcoData(getHandler(), EVENT_PCO_DATA_RECEIVED, null); mDataConfigManager.registerCallback(mDataConfigManagerCallback); + + mDataSettingsManagerCallback = new DataSettingsManagerCallback(getHandler()::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + if (enabled) { + // The NOT_RESTRICTED capability might be changed after data enabled. We + // need to update the capabilities again. + log("Data enabled. update network capabilities."); + updateNetworkCapabilities(); + } + } + + @Override + public void onDataRoamingEnabledChanged(boolean enabled) { + if (enabled) { + // The NOT_RESTRICTED capability might be changed after data roaming + // enabled. We need to update the capabilities again. + log("Data roaming enabled. update network capabilities."); + updateNetworkCapabilities(); + } + } + }; + + mDataNetworkController.getDataSettingsManager() + .registerCallback(mDataSettingsManagerCallback); + mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged( getHandler(), EVENT_DISPLAY_INFO_CHANGED, null); mPhone.getServiceStateTracker().registerForServiceStateChanged(getHandler(), @@ -1126,6 +1201,8 @@ public class DataNetwork extends StateMachine { mPhone.getServiceStateTracker().unregisterForServiceStateChanged(getHandler()); mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged( getHandler()); + mDataNetworkController.getDataSettingsManager() + .unregisterCallback(mDataSettingsManagerCallback); mRil.unregisterForPcoData(getHandler()); mDataConfigManager.unregisterCallback(mDataConfigManagerCallback); } @@ -1157,13 +1234,13 @@ public class DataNetwork extends StateMachine { } case EVENT_ATTACH_NETWORK_REQUEST: { onAttachNetworkRequests((NetworkRequestList) msg.obj); - updateNetworkScore(); + updateNetworkScore(isHandoverInProgress()); break; } case EVENT_DETACH_NETWORK_REQUEST: { onDetachNetworkRequest((TelephonyNetworkRequest) msg.obj, msg.arg1 != 0 /* shouldRetry */); - updateNetworkScore(); + updateNetworkScore(isHandoverInProgress()); break; } case EVENT_DETACH_ALL_NETWORK_REQUESTS: { @@ -1224,6 +1301,14 @@ public class DataNetwork extends StateMachine { loge(eventToString(msg.what) + ": transition to disconnected state"); transitionTo(mDisconnectedState); break; + case EVENT_DATA_NETWORK_VALIDATION_REQUESTED: + // If the data network is not connected, the request should be ignored. + handleErrorDataNetworkValidationRequest((Consumer<Integer>) msg.obj); + break; + case EVENT_DATA_NETWORK_VALIDATION_RESPONSE: + // handle the resultCode in response for the request. + handleDataNetworkValidationRequestResultCode(msg.arg1 /* resultCode */); + break; default: loge("Unhandled event " + eventToString(msg.what)); break; @@ -1238,6 +1323,8 @@ public class DataNetwork extends StateMachine { * @see DataNetwork for the state machine diagram. */ private final class ConnectingState extends State { + /** Used for checking setup response IP mismatch. */ + @NetworkRegistrationInfo.RegistrationState private int mRegStateWhenSetup; @Override public void enter() { sendMessageDelayed(EVENT_STUCK_IN_TRANSIENT_STATE, @@ -1305,11 +1392,149 @@ public class DataNetwork extends StateMachine { mFailCause = DataFailCause.NO_RETRY_FAILURE; transitionTo(mDisconnectedState); break; + case EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE: + int responseCode = msg.arg1; + onDeactivateResponse(responseCode); + break; default: return NOT_HANDLED; } return HANDLED; } + + /** + * Setup a data network. + */ + private void setupData() { + int dataNetworkType = getDataNetworkType(); + + NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); + mRegStateWhenSetup = nri != null + ? nri.getNetworkRegistrationState() + : NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; + // We need to use the actual modem roaming state instead of the framework roaming state + // here. This flag is only passed down to ril_service for picking the correct protocol + // (for old modem backward compatibility). + boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); + + // Set this flag to true if the user turns on data roaming. Or if we override the + // roaming state in framework, we should set this flag to true as well so the modem will + // not reject the data call setup (because the modem thinks the device is roaming). + boolean allowRoaming = mPhone.getDataRoamingEnabled() + || (isModemRoaming && (!mPhone.getServiceState().getDataRoaming() + /*|| isUnmeteredUseOnly()*/)); + + TrafficDescriptor trafficDescriptor = mDataProfile.getTrafficDescriptor(); + final boolean matchAllRuleAllowed = trafficDescriptor == null + || !TextUtils.isEmpty(trafficDescriptor.getDataNetworkName()) + // Both OsAppId and APN name are null. This helps for modem to handle when we + // are on 5G or LTE with URSP support in falling back to default network. + || (TextUtils.isEmpty(trafficDescriptor.getDataNetworkName()) + && trafficDescriptor.getOsAppId() == null); + + int accessNetwork = DataUtils.networkTypeToAccessNetworkType(dataNetworkType); + + mDataServiceManagers.get(mTransport) + .setupDataCall(accessNetwork, mDataProfile, isModemRoaming, allowRoaming, + DataService.REQUEST_REASON_NORMAL, null, mPduSessionId, null, + trafficDescriptor, matchAllRuleAllowed, + obtainMessage(EVENT_SETUP_DATA_NETWORK_RESPONSE)); + + int apnTypeBitmask = mDataProfile.getApnSetting() != null + ? mDataProfile.getApnSetting().getApnTypeBitmask() : ApnSetting.TYPE_NONE; + mDataCallSessionStats.onSetupDataCall(apnTypeBitmask); + + logl("setupData: accessNetwork=" + + AccessNetworkType.toString(accessNetwork) + ", " + mDataProfile + + ", isModemRoaming=" + isModemRoaming + ", allowRoaming=" + allowRoaming + + ", PDU session id=" + mPduSessionId + ", matchAllRuleAllowed=" + + matchAllRuleAllowed); + TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), + ServiceState.networkTypeToRilRadioTechnology(dataNetworkType), + mDataProfile.getProfileId(), mDataProfile.getApn(), + mDataProfile.getProtocolType()); + } + + /** + * Called when receiving setup data network response from the data service. + * + * @param resultCode The result code. + * @param response The response. + */ + private void onSetupResponse(@DataServiceCallback.ResultCode int resultCode, + @Nullable DataCallResponse response) { + logl("onSetupResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode) + + ", response=" + response); + mFailCause = getFailCauseFromDataCallResponse(resultCode, response); + validateDataCallResponse(response, mRegStateWhenSetup); + if (mFailCause == DataFailCause.NONE) { + DataNetwork dataNetwork = mDataNetworkController.getDataNetworkByInterface( + response.getInterfaceName()); + if (dataNetwork != null) { + logl("Interface " + response.getInterfaceName() + " has been already used by " + + dataNetwork + ". Silently tear down now."); + // If this is a pre-5G data setup, that means APN database has some problems. + // For example, different APN settings have the same APN name. + if (response.getTrafficDescriptors().isEmpty() && dataNetwork.isConnected()) { + reportAnomaly("Duplicate network interface " + response.getInterfaceName() + + " detected.", "62f66e7e-8d71-45de-a57b-dc5c78223fd5"); + } + + // Do not actually invoke onTearDown, otherwise the existing data network will + // be torn down. + mRetryDelayMillis = DataCallResponse.RETRY_DURATION_UNDEFINED; + mFailCause = DataFailCause.NO_RETRY_FAILURE; + transitionTo(mDisconnectedState); + return; + } + + updateDataNetwork(response); + + // TODO: Evaluate all network requests and see if each request still can be + // satisfied. + // For requests that can't be satisfied anymore, we need to put them back to the + // unsatisfied pool. If none of network requests can be satisfied, then there is no + // need to mark network agent connected. Just silently deactivate the data network. + if (mAttachedNetworkRequestList.size() == 0) { + log("Tear down the network since there is no live network request."); + // Directly call onTearDown here. Calling tearDown will cause deadlock because + // EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected + // state, which will never happen in this case. + onTearDown(TEAR_DOWN_REASON_NO_LIVE_REQUEST); + return; + } + + if (mVcnManager != null && mVcnManager.applyVcnNetworkPolicy(mNetworkCapabilities, + mLinkProperties).isTeardownRequested()) { + log("VCN service requested to tear down the network."); + // Directly call onTearDown here. Calling tearDown will cause deadlock because + // EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected + // state, which will never happen in this case. + onTearDown(TEAR_DOWN_REASON_VCN_REQUESTED); + return; + } + + transitionTo(mConnectedState); + } else { + // Setup data failed. + mRetryDelayMillis = response != null ? response.getRetryDurationMillis() + : DataCallResponse.RETRY_DURATION_UNDEFINED; + transitionTo(mDisconnectedState); + } + + int apnTypeBitmask = ApnSetting.TYPE_NONE; + int protocol = ApnSetting.PROTOCOL_UNKNOWN; + if (mDataProfile.getApnSetting() != null) { + apnTypeBitmask = mDataProfile.getApnSetting().getApnTypeBitmask(); + protocol = mDataProfile.getApnSetting().getProtocol(); + } + mDataCallSessionStats.onSetupDataCallResponse(response, + getDataNetworkType(), + apnTypeBitmask, + protocol, + // Log the raw fail cause to avoid large amount of UNKNOWN showing on metrics. + response != null ? response.getCause() : mFailCause); + } } /** @@ -1429,6 +1654,10 @@ public class DataNetwork extends StateMachine { updateSuspendState(); updateNetworkCapabilities(); break; + case EVENT_DATA_NETWORK_VALIDATION_REQUESTED: + // Network validation request can be accepted if the data is in connected state + handleDataNetworkValidationRequest((Consumer<Integer>) msg.obj); + break; default: return NOT_HANDLED; } @@ -1447,11 +1676,13 @@ public class DataNetwork extends StateMachine { sendMessageDelayed(EVENT_STUCK_IN_TRANSIENT_STATE, mDataConfigManager.getNetworkHandoverTimeoutMs()); notifyPreciseDataConnectionState(); + updateNetworkScore(true /* keepConnectedForHandover */); } @Override public void exit() { removeMessages(EVENT_STUCK_IN_TRANSIENT_STATE); + updateNetworkScore(false /* keepConnectedForHandover */); } @Override @@ -1481,6 +1712,7 @@ public class DataNetwork extends StateMachine { case EVENT_CSS_INDICATOR_CHANGED: case EVENT_VOICE_CALL_ENDED: case EVENT_VOICE_CALL_STARTED: + case EVENT_DATA_NETWORK_VALIDATION_REQUESTED: // Defer the request until handover succeeds or fails. log("Defer message " + eventToString(msg.what)); deferMessage(msg); @@ -1615,6 +1847,8 @@ public class DataNetwork extends StateMachine { if (mEverConnected) { mLinkStatus = DataCallResponse.LINK_STATUS_INACTIVE; + mNetworkValidationStatus = + PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED; mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback .onLinkStatusChanged(DataNetwork.this, mLinkStatus)); mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback @@ -1951,30 +2185,34 @@ public class DataNetwork extends StateMachine { } } - // Once we set the MMTEL capability, we should never remove it because it's an immutable + // If MMTEL capability is requested, we should not remove it because it's an immutable // capability defined by connectivity service. When the device enters from VoPS to non-VoPS, // we should perform grace tear down from data network controller if needed. - if (mNetworkCapabilities != null - && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)) { - // Previous capability has MMTEL, so add it again. + if (hasNetworkCapabilityInNetworkRequests(NetworkCapabilities.NET_CAPABILITY_MMTEL)) { + // Request has MMTEL, add it again so the network won't be unwanted by connectivity. builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); - } else { + } else if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) { + // Request has IMS capability only. // Always add MMTEL capability on IMS network unless network explicitly indicates VoPS // not supported. - if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); - if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); - if (nri != null) { - DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); - // Check if the network is non-VoPS. - if (dsri != null && dsri.getVopsSupportInfo() != null - && !dsri.getVopsSupportInfo().isVopsSupported() - && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); - } - log("updateNetworkCapabilities: dsri=" + dsri); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); + if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); + if (nri != null) { + DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); + // Check if the network is non-VoPS. + if (dsri != null && dsri.getVopsSupportInfo() != null + && !dsri.getVopsSupportInfo().isVopsSupported() + // Reflect the actual MMTEL if flag on. + && (mFlags.allowMmtelInNonVops() + // Deceive Connectivity service to satisfy an MMTEL request, this should + // be useless because we reach here if no MMTEL request, then removing + // MMTEL capability shouldn't have any impacts. + || !mDataConfigManager.shouldKeepNetworkUpInNonVops( + nri.getNetworkRegistrationState()))) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); } + log("updateNetworkCapabilities: dsri=" + dsri); } } } @@ -2091,6 +2329,10 @@ public class DataNetwork extends StateMachine { } } + if (mDataNetworkController.isEsimBootStrapProvisioningActivated()) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + // If one of the capabilities are for special use, for example, IMS, CBS, then this // network should be restricted, regardless data is enabled or not. if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build()) @@ -2220,54 +2462,6 @@ public class DataNetwork extends StateMachine { } /** - * Setup a data network. - */ - private void setupData() { - int dataNetworkType = getDataNetworkType(); - - // We need to use the actual modem roaming state instead of the framework roaming state - // here. This flag is only passed down to ril_service for picking the correct protocol (for - // old modem backward compatibility). - boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); - - // Set this flag to true if the user turns on data roaming. Or if we override the roaming - // state in framework, we should set this flag to true as well so the modem will not reject - // the data call setup (because the modem actually thinks the device is roaming). - boolean allowRoaming = mPhone.getDataRoamingEnabled() - || (isModemRoaming && (!mPhone.getServiceState().getDataRoaming() - /*|| isUnmeteredUseOnly()*/)); - - TrafficDescriptor trafficDescriptor = mDataProfile.getTrafficDescriptor(); - final boolean matchAllRuleAllowed = trafficDescriptor == null - || !TextUtils.isEmpty(trafficDescriptor.getDataNetworkName()) - // Both OsAppId and APN name are null. This helps for modem to handle when we - // are on 5G or LTE with URSP support in falling back to default network. - || (TextUtils.isEmpty(trafficDescriptor.getDataNetworkName()) - && trafficDescriptor.getOsAppId() == null); - - int accessNetwork = DataUtils.networkTypeToAccessNetworkType(dataNetworkType); - - mDataServiceManagers.get(mTransport) - .setupDataCall(accessNetwork, mDataProfile, isModemRoaming, allowRoaming, - DataService.REQUEST_REASON_NORMAL, null, mPduSessionId, null, - trafficDescriptor, matchAllRuleAllowed, - obtainMessage(EVENT_SETUP_DATA_NETWORK_RESPONSE)); - - int apnTypeBitmask = mDataProfile.getApnSetting() != null - ? mDataProfile.getApnSetting().getApnTypeBitmask() : ApnSetting.TYPE_NONE; - mDataCallSessionStats.onSetupDataCall(apnTypeBitmask); - - logl("setupData: accessNetwork=" - + AccessNetworkType.toString(accessNetwork) + ", " + mDataProfile - + ", isModemRoaming=" + isModemRoaming + ", allowRoaming=" + allowRoaming - + ", PDU session id=" + mPduSessionId + ", matchAllRuleAllowed=" - + matchAllRuleAllowed); - TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), - ServiceState.networkTypeToRilRadioTechnology(dataNetworkType), - mDataProfile.getProfileId(), mDataProfile.getApn(), mDataProfile.getProtocolType()); - } - - /** * Get fail cause from {@link DataCallResponse} and the result code. * * @param resultCode The result code returned from @@ -2419,6 +2613,8 @@ public class DataNetwork extends StateMachine { mTrafficDescriptors.clear(); mTrafficDescriptors.addAll(response.getTrafficDescriptors()); + mDefaultQos = response.getDefaultQos(); + mQosBearerSessions.clear(); mQosBearerSessions.addAll(response.getQosBearerSessions()); if (mQosCallbackTracker != null) { @@ -2444,96 +2640,17 @@ public class DataNetwork extends StateMachine { } updateNetworkCapabilities(); - } - - /** - * Called when receiving setup data network response from the data service. - * - * @param resultCode The result code. - * @param response The response. - */ - private void onSetupResponse(@DataServiceCallback.ResultCode int resultCode, - @Nullable DataCallResponse response) { - logl("onSetupResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode) - + ", response=" + response); - mFailCause = getFailCauseFromDataCallResponse(resultCode, response); - validateDataCallResponse(response, true /*isSetupResponse*/); - if (mFailCause == DataFailCause.NONE) { - DataNetwork dataNetwork = mDataNetworkController.getDataNetworkByInterface( - response.getInterfaceName()); - if (dataNetwork != null) { - logl("Interface " + response.getInterfaceName() + " has been already used by " - + dataNetwork + ". Silently tear down now."); - // If this is a pre-5G data setup, that means APN database has some problems. For - // example, different APN settings have the same APN name. - if (response.getTrafficDescriptors().isEmpty() && dataNetwork.isConnected()) { - reportAnomaly("Duplicate network interface " + response.getInterfaceName() - + " detected.", "62f66e7e-8d71-45de-a57b-dc5c78223fd5"); - } - - // Do not actually invoke onTearDown, otherwise the existing data network will be - // torn down. - mRetryDelayMillis = DataCallResponse.RETRY_DURATION_UNDEFINED; - mFailCause = DataFailCause.NO_RETRY_FAILURE; - transitionTo(mDisconnectedState); - return; - } - - updateDataNetwork(response); - - // TODO: Evaluate all network requests and see if each request still can be satisfied. - // For requests that can't be satisfied anymore, we need to put them back to the - // unsatisfied pool. If none of network requests can be satisfied, then there is no - // need to mark network agent connected. Just silently deactivate the data network. - if (mAttachedNetworkRequestList.size() == 0) { - log("Tear down the network since there is no live network request."); - // Directly call onTearDown here. Calling tearDown will cause deadlock because - // EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected state, - // which will never happen in this case. - onTearDown(TEAR_DOWN_REASON_NO_LIVE_REQUEST); - return; - } - - if (mVcnManager != null && mVcnManager.applyVcnNetworkPolicy(mNetworkCapabilities, - mLinkProperties).isTeardownRequested()) { - log("VCN service requested to tear down the network."); - // Directly call onTearDown here. Calling tearDown will cause deadlock because - // EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected state, - // which will never happen in this case. - onTearDown(TEAR_DOWN_REASON_VCN_REQUESTED); - return; - } - - transitionTo(mConnectedState); - } else { - // Setup data failed. - mRetryDelayMillis = response != null ? response.getRetryDurationMillis() - : DataCallResponse.RETRY_DURATION_UNDEFINED; - transitionTo(mDisconnectedState); - } - - int apnTypeBitmask = ApnSetting.TYPE_NONE; - int protocol = ApnSetting.PROTOCOL_UNKNOWN; - if (mDataProfile.getApnSetting() != null) { - apnTypeBitmask = mDataProfile.getApnSetting().getApnTypeBitmask(); - protocol = mDataProfile.getApnSetting().getProtocol(); - } - mDataCallSessionStats.onSetupDataCallResponse(response, - getDataNetworkType(), - apnTypeBitmask, - protocol, - // Log the raw fail cause to avoid large amount of UNKNOWN showing on metrics. - response != null ? response.getCause() : mFailCause); + updateValidationStatus(response.getNetworkValidationStatus()); } /** * If the {@link DataCallResponse} contains invalid info, triggers an anomaly report. * * @param response The response to be validated - * @param isSetupResponse {@code true} if the response is for initial data call setup + * @param setupRegState Registration state if the response is for initial data call setup. */ private void validateDataCallResponse(@Nullable DataCallResponse response, - boolean isSetupResponse) { + @NetworkRegistrationInfo.RegistrationState int setupRegState) { if (response == null || response.getLinkStatus() == DataCallResponse.LINK_STATUS_INACTIVE) return; int failCause = response.getCause(); @@ -2555,32 +2672,36 @@ public class DataNetwork extends StateMachine { } // Check IP for initial setup response NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); - if (isSetupResponse + if (setupRegState != -1 // Is setup response && mDataProfile.getApnSetting() != null && nri != null && nri.isInService()) { + boolean wasRoaming = setupRegState + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; boolean isRoaming = nri.getNetworkRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; - int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() - : mDataProfile.getApnSetting().getProtocol(); - String underlyingDataService = mTransport - == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - ? "RIL" : "IWLAN data service"; - if (protocol == ApnSetting.PROTOCOL_IP) { - if (response.getAddresses().stream().anyMatch( - la -> la.getAddress() instanceof java.net.Inet6Address)) { - loge("Invalid DataCallResponse. Requested IPv4 but got IPv6 address. " - + response); - reportAnomaly(underlyingDataService + " reported mismatched IP " - + "type. Requested IPv4 but got IPv6 address.", - "7744f920-fb64-4db0-ba47-de0eae485a80"); - } - } else if (protocol == ApnSetting.PROTOCOL_IPV6) { - if (response.getAddresses().stream().anyMatch( - la -> la.getAddress() instanceof java.net.Inet4Address)) { - loge("Invalid DataCallResponse. Requested IPv6 but got IPv4 address. " - + response); - reportAnomaly(underlyingDataService + " reported mismatched IP " - + "type. Requested IPv6 but got IPv4 address.", - "7744f920-fb64-4db0-ba47-de0eae485a80"); + if (wasRoaming == isRoaming) { // Ignore check if in race condition. + int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() + : mDataProfile.getApnSetting().getProtocol(); + String underlyingDataService = mTransport + == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + ? "RIL" : "IWLAN data service"; + if (protocol == ApnSetting.PROTOCOL_IP) { + if (response.getAddresses().stream().anyMatch( + la -> la.getAddress() instanceof java.net.Inet6Address)) { + loge("Invalid DataCallResponse. Requested IPv4 but got IPv6 address." + + response); + reportAnomaly(underlyingDataService + " reported mismatched IP " + + "type. Requested IPv4 but got IPv6 address.", + "7744f920-fb64-4db0-ba47-de0eae485a81"); + } + } else if (protocol == ApnSetting.PROTOCOL_IPV6) { + if (response.getAddresses().stream().anyMatch( + la -> la.getAddress() instanceof java.net.Inet4Address)) { + loge("Invalid DataCallResponse. Requested IPv6 but got IPv4 address." + + response); + reportAnomaly(underlyingDataService + " reported mismatched IP " + + "type. Requested IPv6 but got IPv4 address.", + "7744f920-fb64-4db0-ba47-de0eae485a81"); + } } } } @@ -2653,7 +2774,7 @@ public class DataNetwork extends StateMachine { public boolean shouldDelayImsTearDownDueToInCall() { return mDataConfigManager.isImsDelayTearDownUntilVoiceCallEndEnabled() && mNetworkCapabilities != null - && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) + && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) && mPhone.getImsPhone() != null && mPhone.getImsPhone().getCallTracker().getState() != PhoneConstants.State.IDLE; @@ -2717,7 +2838,7 @@ public class DataNetwork extends StateMachine { if (response != null) { if (!response.equals(mDataCallResponse)) { log("onDataStateChanged: " + response); - validateDataCallResponse(response, false /*isSetupResponse*/); + validateDataCallResponse(response, -1 /*setupRegState setup only*/); mDataCallResponse = response; if (response.getLinkStatus() != DataCallResponse.LINK_STATUS_INACTIVE) { updateDataNetwork(response); @@ -2978,39 +3099,23 @@ public class DataNetwork extends StateMachine { return mLinkStatus; } + /** * Update the network score and report to connectivity service if necessary. - */ - private void updateNetworkScore() { - int networkScore = getNetworkScore(); - if (networkScore != mNetworkScore) { - logl("Updating score from " + mNetworkScore + " to " + networkScore); - mNetworkScore = networkScore; + * + * @param keepConnectedForHandover indicate handover is in progress or not. + */ + private void updateNetworkScore(boolean keepConnectedForHandover) { + int connectedReason = keepConnectedForHandover + ? NetworkScore.KEEP_CONNECTED_FOR_HANDOVER : NetworkScore.KEEP_CONNECTED_NONE; + if (mNetworkScore.getKeepConnectedReason() != connectedReason) { + mNetworkScore = new NetworkScore.Builder() + .setKeepConnectedReason(connectedReason).build(); mNetworkAgent.sendNetworkScore(mNetworkScore); } } /** - * @return The network score. The higher score of the network has higher chance to be - * selected by the connectivity service as active network. - */ - private int getNetworkScore() { - // If it's serving a network request that asks NET_CAPABILITY_INTERNET and doesn't have - // specify a sub id, this data network is considered to be default internet data - // connection. In this case we assign a slightly higher score of 50. The intention is - // it will not be replaced by other data networks accidentally in DSDS use case. - int score = OTHER_NETWORK_SCORE; - for (TelephonyNetworkRequest networkRequest : mAttachedNetworkRequestList) { - if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && networkRequest.getNetworkSpecifier() == null) { - score = DEFAULT_INTERNET_NETWORK_SCORE; - } - } - - return score; - } - - /** * @return Network registration info on the current transport. */ private @Nullable NetworkRegistrationInfo getNetworkRegistrationInfo() { @@ -3154,13 +3259,7 @@ public class DataNetwork extends StateMachine { * @return {@code true} if this data network supports internet. */ public boolean isInternetSupported() { - return mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && mNetworkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - && mNetworkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_TRUSTED) - && mNetworkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VPN); + return mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } /** @@ -3185,6 +3284,8 @@ public class DataNetwork extends StateMachine { .setLinkProperties(mLinkProperties) .setNetworkType(getDataNetworkType()) .setFailCause(mFailCause) + .setDefaultQos(mDefaultQos) + .setNetworkValidationStatus(mNetworkValidationStatus) .build(); } @@ -3261,7 +3362,9 @@ public class DataNetwork extends StateMachine { && !mAttachedNetworkRequestList.isEmpty()) { TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0); DataProfile dataProfile = mDataNetworkController.getDataProfileManager() - .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, false); + .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, + mPhone.getServiceState().isUsingNonTerrestrialNetwork(), + mDataNetworkController.isEsimBootStrapProvisioningActivated(), false); // Some carriers have different profiles between cellular and IWLAN. We need to // dynamically switch profile, but only when those profiles have same APN name. if (dataProfile != null && dataProfile.getApnSetting() != null @@ -3298,7 +3401,7 @@ public class DataNetwork extends StateMachine { logl("onHandoverResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode) + ", response=" + response); mFailCause = getFailCauseFromDataCallResponse(resultCode, response); - validateDataCallResponse(response, false /*isSetupResponse*/); + validateDataCallResponse(response, -1 /*setupRegState setup only*/); if (mFailCause == DataFailCause.NONE) { // Handover succeeded. @@ -3453,6 +3556,81 @@ public class DataNetwork extends StateMachine { } /** + * The network validation requests moves to process on the statemachich handler. A request is + * processed according to state of the data network. + */ + public void requestNetworkValidation(@NonNull Consumer<Integer> resultCodeCallback) { + // request a network validation by DataNetwork state + sendMessage(EVENT_DATA_NETWORK_VALIDATION_REQUESTED, resultCodeCallback); + } + + /** + * Request network validation to data service provider. + */ + private void handleDataNetworkValidationRequest(@NonNull Consumer<Integer> resultCodeCallback) { + if (mNetworkValidationResultCodeCallback != null) { + loge("requestNetworkValidation: previous networkValidationRequest is in progress."); + FunctionalUtils.ignoreRemoteException(resultCodeCallback::accept) + .accept(DataServiceCallback.RESULT_ERROR_BUSY); + return; + } + + mNetworkValidationResultCodeCallback = resultCodeCallback; + + // Request validation directly from the data service. + mDataServiceManagers.get(mTransport).requestValidation( + mCid.get(mTransport), obtainMessage(EVENT_DATA_NETWORK_VALIDATION_RESPONSE)); + log("handleDataNetworkValidationRequest, network validation requested"); + } + + private void handleErrorDataNetworkValidationRequest( + @NonNull Consumer<Integer> resultCodeCallback) { + loge("handleErrorDataNetworkValidationRequest: DataNetwork is not in Connected state"); + FunctionalUtils.ignoreRemoteException(resultCodeCallback::accept) + .accept(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + + /** + * handle the resultCode in response for the request. + * + * @param resultCode {@link DataServiceCallback.ResultCode} + */ + private void handleDataNetworkValidationRequestResultCode( + @DataServiceCallback.ResultCode int resultCode) { + if (mNetworkValidationResultCodeCallback != null) { + log("handleDataNetworkValidationRequestResultCode, resultCode:" + + DataServiceCallback.resultCodeToString(resultCode)); + FunctionalUtils.ignoreRemoteException(mNetworkValidationResultCodeCallback::accept) + .accept(resultCode); + mNetworkValidationResultCodeCallback = null; + } + } + + /** + * Update the validation status from {@link DataCallResponse}, convert to network validation + * status {@link PreciseDataConnectionState.NetworkValidationStatus} and notify to + * {@link PreciseDataConnectionState} if status was changed. + * + * @param networkValidationStatus {@link PreciseDataConnectionState.NetworkValidationStatus} + */ + private void updateValidationStatus( + @PreciseDataConnectionState.NetworkValidationStatus int networkValidationStatus) { + if (!mFlags.networkValidation()) { + // Do nothing, if network validation feature is disabled + return; + } + + // if network validation status is changed, notify preciseDataConnectionState. + if (mNetworkValidationStatus != networkValidationStatus) { + log("updateValidationStatus:" + + PreciseDataConnectionState.networkValidationStatusToString( + networkValidationStatus)); + mNetworkValidationStatus = networkValidationStatus; + notifyPreciseDataConnectionState(); + } + } + + /** * Convert the data tear down reason to string. * * @param reason Data deactivation reason. @@ -3478,6 +3656,8 @@ public class DataNetwork extends StateMachine { return "TEAR_DOWN_REASON_ROAMING_DISABLED"; case TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED: return "TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED"; + case TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED: + return "TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED"; case TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY: return "TEAR_DOWN_REASON_DATA_SERVICE_NOT_READY"; case TEAR_DOWN_REASON_POWER_OFF_BY_CARRIER: @@ -3583,6 +3763,10 @@ public class DataNetwork extends StateMachine { return "EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE"; case EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE: return "EVENT_NOTIFY_HANDOVER_CANCELLED_RESPONSE"; + case EVENT_DATA_NETWORK_VALIDATION_REQUESTED: + return "EVENT_DATA_NETWORK_VALIDATION_REQUESTED"; + case EVENT_DATA_NETWORK_VALIDATION_RESPONSE: + return "EVENT_DATA_NETWORK_VALIDATION_RESPONSE"; default: return "Unknown(" + event + ")"; } diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index f9e7510612..63fe7e5cdd 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -60,10 +60,12 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.DataState; import android.telephony.TelephonyManager.SimState; import android.telephony.TelephonyRegistryManager; +import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.HandoverFailureMode; import android.telephony.data.DataCallResponse.LinkStatus; import android.telephony.data.DataProfile; +import android.telephony.data.DataServiceCallback; import android.telephony.ims.ImsException; import android.telephony.ims.ImsManager; import android.telephony.ims.ImsReasonInfo; @@ -99,8 +101,12 @@ import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryEntry; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; import com.android.internal.telephony.data.DataStallRecoveryManager.DataStallRecoveryManagerCallback; import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.ims.ImsResolver; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.TelephonyUtils; +import com.android.internal.util.FunctionalUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -112,6 +118,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -122,6 +129,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -296,6 +304,9 @@ public class DataNetworkController extends Handler { */ private @DataState int mInternetDataNetworkState = TelephonyManager.DATA_DISCONNECTED; + /** All the current connected/handover internet networks. */ + @NonNull private Set<DataNetwork> mConnectedInternetNetworks = new HashSet<>(); + /** * The IMS data network state. For now this is just for debugging purposes. */ @@ -379,6 +390,8 @@ public class DataNetworkController extends Handler { /** True after try to release an IMS network; False after try to request an IMS network. */ private boolean mLastImsOperationIsRelease; + private final @NonNull FeatureFlags mFeatureFlags; + /** The broadcast receiver. */ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override @@ -559,12 +572,13 @@ public class DataNetworkController extends Handler { @ValidationStatus int validationStatus) {} /** - * Called when internet data network is connected. + * Called when a network that's capable of internet is newly connected or disconnected. * * @param internetNetworks The connected internet data network. It should be only one in * most of the cases. */ - public void onInternetDataNetworkConnected(@NonNull List<DataNetwork> internetNetworks) {} + public void onConnectedInternetDataNetworksChanged(@NonNull Set<DataNetwork> + internetNetworks) {} /** * Called when data network is connected. @@ -575,9 +589,6 @@ public class DataNetworkController extends Handler { public void onDataNetworkConnected(@TransportType int transport, @NonNull DataProfile dataProfile) {} - /** Called when internet data network is disconnected. */ - public void onInternetDataNetworkDisconnected() {} - /** * Called when any data network existing status changed. * @@ -793,10 +804,13 @@ public class DataNetworkController extends Handler { * @param phone The phone instance. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. + * @param featureFlags The feature flag. */ - public DataNetworkController(@NonNull Phone phone, @NonNull Looper looper) { + public DataNetworkController(@NonNull Phone phone, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags) { super(looper); mPhone = phone; + mFeatureFlags = featureFlags; mLogTag = "DNC-" + mPhone.getPhoneId(); log("DataNetworkController created."); @@ -805,7 +819,7 @@ public class DataNetworkController extends Handler { mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, transport)); } - mDataConfigManager = new DataConfigManager(mPhone, looper); + mDataConfigManager = new DataConfigManager(mPhone, looper, featureFlags); // ========== Anomaly counters ========== mImsThrottleCounter = new SlidingWindowEventCounter( @@ -871,6 +885,7 @@ public class DataNetworkController extends Handler { DataProfileManager.class.getName()) .makeDataProfileManager(mPhone, this, mDataServiceManagers .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper, + mFeatureFlags, new DataProfileManagerCallback(this::post) { @Override public void onDataProfilesChanged() { @@ -891,7 +906,7 @@ public class DataNetworkController extends Handler { } }); mDataRetryManager = new DataRetryManager(mPhone, this, - mDataServiceManagers, looper, + mDataServiceManagers, looper, mFeatureFlags, new DataRetryManagerCallback(this::post) { @Override public void onDataNetworkSetupRetry( @@ -1290,6 +1305,7 @@ public class DataNetworkController extends Handler { * {@link #onAttachNetworkRequestsFailed(DataNetwork, NetworkRequestList)} will be invoked. */ private boolean findCompatibleDataNetworkAndAttach(@NonNull NetworkRequestList requestList) { + if (requestList.isEmpty()) return false; // Try to find a data network that can satisfy all the network requests. for (DataNetwork dataNetwork : mDataNetworkList) { TelephonyNetworkRequest networkRequest = requestList.stream() @@ -1307,6 +1323,28 @@ public class DataNetworkController extends Handler { // When reaching here, it means this data network can satisfy all the network requests. logv("Found a compatible data network " + dataNetwork + ". Attaching " + requestList); + + // If WLAN preferred, see whether a more suitable data profile shall be used to satisfy + // a short-lived request that doesn't perform handover. + int capability = requestList.getFirst().getApnTypeNetworkCapability(); + int preferredTransport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability(capability); + if (capability == NetworkCapabilities.NET_CAPABILITY_MMS + && preferredTransport != dataNetwork.getTransport() + && preferredTransport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + DataProfile candidate = mDataProfileManager + .getDataProfileForNetworkRequest(requestList.getFirst(), + TelephonyManager.NETWORK_TYPE_IWLAN, + mServiceState.isUsingNonTerrestrialNetwork(), + isEsimBootStrapProvisioningActivated(), + false/*ignorePermanentFailure*/); + if (candidate != null && !dataNetwork.getDataProfile().equals(candidate)) { + logv("But skipped because found better data profile " + candidate + + DataUtils.networkCapabilityToString(capability) + " preferred on " + + AccessNetworkConstants.transportTypeToString(preferredTransport)); + continue; + } + } return dataNetwork.attachNetworkRequests(requestList); } return false; @@ -1462,7 +1500,9 @@ public class DataNetworkController extends Handler { if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) { evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST); evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest( - networkRequest, getDataNetworkType(transport), true)); + networkRequest, getDataNetworkType(transport), + mServiceState.isUsingNonTerrestrialNetwork(), + isEsimBootStrapProvisioningActivated(), true)); networkRequest.setEvaluation(evaluation); log(evaluation.toString()); return evaluation; @@ -1497,7 +1537,9 @@ public class DataNetworkController extends Handler { if (nri != null) { DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); if (dsri != null && dsri.getVopsSupportInfo() != null - && !dsri.getVopsSupportInfo().isVopsSupported()) { + && !dsri.getVopsSupportInfo().isVopsSupported() + && !mDataConfigManager.allowBringUpNetworkInNonVops( + nri.getNetworkRegistrationState())) { evaluation.addDataDisallowedReason(DataDisallowedReason.VOPS_NOT_SUPPORTED); } } @@ -1548,6 +1590,11 @@ public class DataNetworkController extends Handler { evaluation.addDataDisallowedReason(DataDisallowedReason.CDMA_EMERGENCY_CALLBACK_MODE); } + // Check whether data is disallowed while using satellite + if (isDataDisallowedDueToSatellite(networkRequest.getCapabilities())) { + evaluation.addDataDisallowedReason(DataDisallowedReason.SERVICE_OPTION_NOT_SUPPORTED); + } + // Check if only one data network is allowed. if (isOnlySingleDataNetworkAllowed(transport) && !hasCapabilityExemptsFromSinglePdnRule(networkRequest.getCapabilities())) { @@ -1613,6 +1660,8 @@ public class DataNetworkController extends Handler { } DataProfile dataProfile = mDataProfileManager .getDataProfileForNetworkRequest(networkRequest, networkType, + mServiceState.isUsingNonTerrestrialNetwork(), + isEsimBootStrapProvisioningActivated(), // If the evaluation is due to environmental changes, then we should ignore // the permanent failure reached earlier. reason.isConditionBased()); @@ -1725,6 +1774,12 @@ public class DataNetworkController extends Handler { evaluation.addDataDisallowedReason(DataDisallowedReason.CDMA_EMERGENCY_CALLBACK_MODE); } + // Check whether data is disallowed while using satellite + if (isDataDisallowedDueToSatellite(dataNetwork.getNetworkCapabilities() + .getCapabilities())) { + evaluation.addDataDisallowedReason(DataDisallowedReason.SERVICE_OPTION_NOT_SUPPORTED); + } + // Check if there are other network that has higher priority, and only single data network // is allowed. if (isOnlySingleDataNetworkAllowed(dataNetwork.getTransport()) @@ -1747,6 +1802,8 @@ public class DataNetworkController extends Handler { } } + // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL + // capability is dynamically added when moving between vops and nonvops area. boolean vopsIsRequired = dataNetwork.hasNetworkCapabilityInNetworkRequests( NetworkCapabilities.NET_CAPABILITY_MMTEL); @@ -1769,7 +1826,8 @@ public class DataNetworkController extends Handler { DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); if (dsri != null && dsri.getVopsSupportInfo() != null && !dsri.getVopsSupportInfo().isVopsSupported() - && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) { + && !mDataConfigManager.shouldKeepNetworkUpInNonVops( + nri.getNetworkRegistrationState())) { evaluation.addDataDisallowedReason( DataDisallowedReason.VOPS_NOT_SUPPORTED); } @@ -1949,6 +2007,8 @@ public class DataNetworkController extends Handler { } // Check if VoPS is required, but the target transport is non-VoPS. + // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL + // capability is dynamically added when moving between vops and nonvops area. NetworkRequestList networkRequestList = dataNetwork.getAttachedNetworkRequestList(); if (networkRequestList.stream().anyMatch(request @@ -1957,7 +2017,8 @@ public class DataNetworkController extends Handler { // Check if the network is non-VoPS. if (dsri != null && dsri.getVopsSupportInfo() != null && !dsri.getVopsSupportInfo().isVopsSupported() - && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) { + && !mDataConfigManager.shouldKeepNetworkUpInNonVops( + nri.getNetworkRegistrationState())) { dataEvaluation.addDataDisallowedReason( DataDisallowedReason.VOPS_NOT_SUPPORTED); } @@ -2067,6 +2128,8 @@ public class DataNetworkController extends Handler { return DataNetwork.TEAR_DOWN_REASON_SIM_REMOVAL; case CONCURRENT_VOICE_DATA_NOT_ALLOWED: return DataNetwork.TEAR_DOWN_REASON_CONCURRENT_VOICE_DATA_NOT_ALLOWED; + case SERVICE_OPTION_NOT_SUPPORTED: + return DataNetwork.TEAR_DOWN_REASON_SERVICE_OPTION_NOT_SUPPORTED; case RADIO_POWER_OFF: return DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON; case PENDING_TEAR_DOWN_ALL: @@ -2113,8 +2176,7 @@ public class DataNetworkController extends Handler { for (DataNetwork dataNetwork : mDataNetworkList) { if (dataNetwork.getId() == cid && dataNetwork.isConnected() - && dataNetwork.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + && dataNetwork.isInternetSupported()) { return true; } } @@ -2219,6 +2281,22 @@ public class DataNetworkController extends Handler { } /** + * Check if the device is in eSIM bootstrap provisioning state. + * + * @return {@code true} if the device is under eSIM bootstrap provisioning. + */ + public boolean isEsimBootStrapProvisioningActivated() { + if (!mFeatureFlags.esimBootstrapProvisioningFlag()) { + return false; + } + + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(mPhone.getSubId()); + return subInfo != null + && subInfo.getProfileClass() == SubscriptionManager.PROFILE_CLASS_PROVISIONING; + } + + /** * Register for IMS feature registration state. * * @param subId The subscription index. @@ -2500,8 +2578,8 @@ public class DataNetworkController extends Handler { + AccessNetworkConstants.transportTypeToString(transport) + " with " + dataProfile + ", and attaching " + networkRequestList.size() + " network requests to it."); - mDataNetworkList.add(new DataNetwork(mPhone, getLooper(), mDataServiceManagers, - dataProfile, networkRequestList, transport, allowedReason, + mDataNetworkList.add(new DataNetwork(mPhone, mFeatureFlags, getLooper(), + mDataServiceManagers, dataProfile, networkRequestList, transport, allowedReason, new DataNetworkCallback(this::post) { @Override public void onSetupDataFailed(@NonNull DataNetwork dataNetwork, @@ -2704,7 +2782,7 @@ public class DataNetworkController extends Handler { mPreviousConnectedDataNetworkList.remove(MAX_HISTORICAL_CONNECTED_DATA_NETWORKS); } - updateOverallInternetDataState(); + if (dataNetwork.isInternetSupported()) updateOverallInternetDataState(); if (dataNetwork.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS)) { @@ -2896,7 +2974,7 @@ public class DataNetworkController extends Handler { */ private void onDataNetworkSuspendedStateChanged(@NonNull DataNetwork dataNetwork, boolean suspended) { - updateOverallInternetDataState(); + if (dataNetwork.isInternetSupported()) updateOverallInternetDataState(); if (dataNetwork.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS)) { @@ -2923,7 +3001,7 @@ public class DataNetworkController extends Handler { mDataNetworkList.remove(dataNetwork); mPendingImsDeregDataNetworks.remove(dataNetwork); mDataRetryManager.cancelPendingHandoverRetry(dataNetwork); - updateOverallInternetDataState(); + if (dataNetwork.isInternetSupported()) updateOverallInternetDataState(); if (dataNetwork.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS)) { @@ -3195,9 +3273,12 @@ public class DataNetworkController extends Handler { logl("Start handover " + dataNetwork + " to " + AccessNetworkConstants.transportTypeToString(targetTransport)); dataNetwork.startHandover(targetTransport, dataHandoverRetryEntry); - } else if (dataEvaluation.containsOnly(DataDisallowedReason.NOT_IN_SERVICE) - && dataNetwork.shouldDelayImsTearDownDueToInCall()) { - // We try to preserve voice call in the case of temporary preferred transport mismatch + } else if (dataNetwork.shouldDelayImsTearDownDueToInCall() + && (dataEvaluation.containsOnly(DataDisallowedReason.NOT_IN_SERVICE) + || mFeatureFlags.relaxHoTeardown() && dataEvaluation.isSubsetOf( + DataDisallowedReason.NOT_IN_SERVICE, + DataDisallowedReason.NOT_ALLOWED_BY_POLICY))) { + // We try our best to preserve the voice call by retrying later if (dataHandoverRetryEntry != null) { dataHandoverRetryEntry.setState(DataRetryEntry.RETRY_STATE_FAILED); } @@ -3319,8 +3400,7 @@ public class DataNetworkController extends Handler { dataNetwork.attachNetworkRequests(networkRequestList); } - if (dataNetwork.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + if (dataNetwork.isInternetSupported()) { // Update because DataNetwork#isInternetSupported might have changed with capabilities. updateOverallInternetDataState(); } @@ -3343,7 +3423,12 @@ public class DataNetworkController extends Handler { } if (oldNri.getAccessNetworkTechnology() != newNri.getAccessNetworkTechnology() - || (!oldNri.isRoaming() && newNri.isRoaming())) { + // Some CarrierConfig disallows vops in nonVops area for specified home/roaming. + || (oldNri.isRoaming() != newNri.isRoaming())) { + return true; + } + + if (!oldNri.isNonTerrestrialNetwork() && newNri.isNonTerrestrialNetwork()) { return true; } @@ -3389,7 +3474,8 @@ public class DataNetworkController extends Handler { if (oldPsNri == null || oldPsNri.getAccessNetworkTechnology() != newPsNri.getAccessNetworkTechnology() || (!oldPsNri.isInService() && newPsNri.isInService()) - || (oldPsNri.isRoaming() && !newPsNri.isRoaming())) { + // Some CarrierConfig allows vops in nonVops area for specified home/roaming. + || (oldPsNri.isRoaming() != newPsNri.isRoaming())) { return true; } @@ -3399,6 +3485,10 @@ public class DataNetworkController extends Handler { return true; } + if (oldSS.isUsingNonTerrestrialNetwork() && !newSS.isUsingNonTerrestrialNetwork()) { + return true; + } + DataSpecificRegistrationInfo oldDsri = oldPsNri.getDataSpecificInfo(); DataSpecificRegistrationInfo newDsri = newPsNri.getDataSpecificInfo(); @@ -3447,7 +3537,12 @@ public class DataNetworkController extends Handler { oldNri.getRegistrationState()) : null); debugMessage.append("->").append(newNri != null ? NetworkRegistrationInfo.registrationStateToString( - newNri.getRegistrationState()) : null).append("] "); + newNri.getRegistrationState()) : null).append(", "); + debugMessage.append(oldNri != null ? NetworkRegistrationInfo + .isNonTerrestrialNetworkToString(oldNri.isNonTerrestrialNetwork()) : null); + debugMessage.append("->").append(newNri != null ? NetworkRegistrationInfo + .isNonTerrestrialNetworkToString(newNri.isNonTerrestrialNetwork()) : null) + .append("] "); if (shouldReevaluateDataNetworks(oldNri, newNri)) { if (!hasMessages(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)) { sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS, @@ -3484,11 +3579,11 @@ public class DataNetworkController extends Handler { .anyMatch(dataNetwork -> dataNetwork.isInternetSupported() && (dataNetwork.isConnected() || dataNetwork.isHandoverInProgress())); // If any one is not suspended, then the overall is not suspended. - List<DataNetwork> allConnectedInternetDataNetworks = mDataNetworkList.stream() + Set<DataNetwork> allConnectedInternetDataNetworks = mDataNetworkList.stream() .filter(DataNetwork::isInternetSupported) .filter(dataNetwork -> dataNetwork.isConnected() || dataNetwork.isHandoverInProgress()) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); boolean isSuspended = !allConnectedInternetDataNetworks.isEmpty() && allConnectedInternetDataNetworks.stream().allMatch(DataNetwork::isSuspended); logv("isSuspended=" + isSuspended + ", anyInternetConnected=" + anyInternetConnected @@ -3505,19 +3600,15 @@ public class DataNetworkController extends Handler { logl("Internet data state changed from " + TelephonyUtils.dataStateToString(mInternetDataNetworkState) + " to " + TelephonyUtils.dataStateToString(dataNetworkState) + "."); - // TODO: Create a new route to notify TelephonyRegistry. - if (dataNetworkState == TelephonyManager.DATA_CONNECTED - && mInternetDataNetworkState == TelephonyManager.DATA_DISCONNECTED) { - mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( - () -> callback.onInternetDataNetworkConnected( - allConnectedInternetDataNetworks))); - } else if (dataNetworkState == TelephonyManager.DATA_DISCONNECTED - && mInternetDataNetworkState == TelephonyManager.DATA_CONNECTED) { - mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( - callback::onInternetDataNetworkDisconnected)); - } // TODO: Add suspended callback if needed. mInternetDataNetworkState = dataNetworkState; } + // Check data network reference equality to update current connected internet networks. + if (!mConnectedInternetNetworks.equals(allConnectedInternetDataNetworks)) { + mConnectedInternetNetworks = allConnectedInternetDataNetworks; + mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( + () -> callback.onConnectedInternetDataNetworksChanged( + allConnectedInternetDataNetworks))); + } } /** @@ -3765,6 +3856,78 @@ public class DataNetworkController extends Handler { } /** + * Check whether data is disallowed while using satellite + * @param capabilities An array of the NetworkCapabilities to be checked + * @return {@code true} if the capabilities contain any capability that are restricted + * while using satellite else {@code false} + */ + private boolean isDataDisallowedDueToSatellite(@NetCapability int[] capabilities) { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + return false; + } + + if (!mServiceState.isUsingNonTerrestrialNetwork()) { + // Device is not connected to satellite + return false; + } + + Set<Integer> restrictedCapabilities = Set.of(NetworkCapabilities.NET_CAPABILITY_INTERNET); + if (Arrays.stream(capabilities).noneMatch(restrictedCapabilities::contains)) { + // Only internet data disallowed while using satellite + return false; + } + + for (NetworkRegistrationInfo nri : mServiceState.getNetworkRegistrationInfoList()) { + if (nri.isNonTerrestrialNetwork() + && nri.getAvailableServices().contains( + NetworkRegistrationInfo.SERVICE_TYPE_DATA)) { + // Data is supported while using satellite + return false; + } + } + + // Data is disallowed while using satellite + return true; + } + + /** + * Request network validation. + * + * Nnetwork validation request is sent to the DataNetwork that matches the network capability + * in the list of DataNetwork owned by the DNC. + * + * @param capability network capability {@link NetCapability} + */ + public void requestNetworkValidation(@NetCapability int capability, + @NonNull Consumer<Integer> resultCodeCallback) { + + if (DataUtils.networkCapabilityToApnType(capability) == ApnSetting.TYPE_NONE) { + // If the capability is not an apn type based capability, sent an invalid argument. + loge("requestNetworkValidation: the capability is not an apn type based. capability:" + + capability); + FunctionalUtils.ignoreRemoteException(resultCodeCallback::accept) + .accept(DataServiceCallback.RESULT_ERROR_INVALID_ARG); + return; + } + + // Find DataNetwork that matches the capability. + List<DataNetwork> list = mDataNetworkList.stream() + .filter(dataNetwork -> + dataNetwork.getNetworkCapabilities().hasCapability(capability)) + .toList(); + + if (!list.isEmpty()) { + // request network validation. + list.forEach(dataNetwork -> dataNetwork.requestNetworkValidation(resultCodeCallback)); + } else { + // If not found, sent an invalid argument. + loge("requestNetworkValidation: No matching DataNetwork was found"); + FunctionalUtils.ignoreRemoteException(resultCodeCallback::accept) + .accept(DataServiceCallback.RESULT_ERROR_INVALID_ARG); + } + } + + /** * Log debug messages. * @param s debug messages */ diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 0878ccf48a..b4055a3e4c 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -48,6 +48,7 @@ import android.util.LocalLog; import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -113,6 +114,9 @@ public class DataProfileManager extends Handler { /** SIM state. */ private @SimState int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; + /** Feature flags controlling which feature is enabled. */ + private final @NonNull FeatureFlags mFeatureFlags; + /** * Data profile manager callback. This should be only used by {@link DataNetworkController}. */ @@ -140,15 +144,18 @@ public class DataProfileManager extends Handler { * @param dataServiceManager WWAN data service manager. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. + * @param featureFlags Feature flags controlling which feature is enabled. * @param callback Data profile manager callback. */ public DataProfileManager(@NonNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags, @NonNull DataProfileManagerCallback callback) { super(looper); mPhone = phone; mLogTag = "DPM-" + mPhone.getPhoneId(); + mFeatureFlags = featureFlags; mDataNetworkController = dataNetworkController; mWwanDataServiceManager = dataServiceManager; mDataConfigManager = dataNetworkController.getDataConfigManager(); @@ -163,8 +170,9 @@ public class DataProfileManager extends Handler { mDataNetworkController.registerDataNetworkControllerCallback( new DataNetworkControllerCallback(this::post) { @Override - public void onInternetDataNetworkConnected( - @NonNull List<DataNetwork> internetNetworks) { + public void onConnectedInternetDataNetworksChanged( + @NonNull Set<DataNetwork> internetNetworks) { + if (internetNetworks.isEmpty()) return; DataProfileManager.this.onInternetDataNetworkConnected(internetNetworks); } @@ -247,6 +255,7 @@ public class DataProfileManager extends Handler { cursor.close(); return dataProfile; } + /** * Update all data profiles, including preferred data profile, and initial attach data profile. * Also send those profiles down to the modem if needed. @@ -405,27 +414,40 @@ public class DataProfileManager extends Handler { } /** - * Called when internet data is connected. + * Called when new internet data connect. * * @param internetNetworks The connected internet data networks. */ - private void onInternetDataNetworkConnected(@NonNull List<DataNetwork> internetNetworks) { + private void onInternetDataNetworkConnected(@NonNull Set<DataNetwork> internetNetworks) { DataProfile defaultProfile = null; - if (internetNetworks.size() == 1) { + if (mFeatureFlags.refinePreferredDataProfileSelection()) { // Most of the cases there should be only one. - defaultProfile = internetNetworks.get(0).getDataProfile(); - } else if (internetNetworks.size() > 1) { // but in case there are multiple, find the default internet network, and choose the // one which has longest life cycle. - logv("onInternetDataNetworkConnected: mPreferredDataProfile=" + mPreferredDataProfile - + " internetNetworks=" + internetNetworks); defaultProfile = internetNetworks.stream() .filter(network -> mPreferredDataProfile == null + // Find the one most resembles the current preferred profile, + // avoiding e.g. DUN default network. || canPreferredDataProfileSatisfy( network.getAttachedNetworkRequestList())) .map(DataNetwork::getDataProfile) .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp)) .orElse(null); + } else { + if (internetNetworks.size() == 1) { + // Most of the cases there should be only one. + defaultProfile = internetNetworks.stream().findFirst().get().getDataProfile(); + } else if (internetNetworks.size() > 1) { + // but in case there are multiple, find the default internet network, and choose the + // one which has longest life cycle. + defaultProfile = internetNetworks.stream() + .filter(network -> mPreferredDataProfile == null + || canPreferredDataProfileSatisfy( + network.getAttachedNetworkRequestList())) + .map(DataNetwork::getDataProfile) + .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp)) + .orElse(null); + } } // Update a working internet data profile as a future candidate for preferred data profile @@ -436,6 +458,9 @@ public class DataProfileManager extends Handler { // brought up a network means it passed sophisticated checks, update the preferred data // profile so that this network won't be torn down in future network evaluations. if (defaultProfile == null || defaultProfile.equals(mPreferredDataProfile)) return; + logv("onInternetDataNetworkConnected: defaultProfile=" + defaultProfile + + " previous preferredDataProfile=" + mPreferredDataProfile + + " internetNetworks=" + internetNetworks); // Save the preferred data profile into database. setPreferredDataProfile(defaultProfile); updateDataProfiles(false/*force update IA*/); @@ -627,18 +652,19 @@ public class DataProfileManager extends Handler { * * @param networkRequest The network request. * @param networkType The current data network type. + * @param isNtn {@code true} if the device is currently attached to non-terrestrial network. * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}. * This should be set to true for condition-based retry/setup. * @return The data profile. {@code null} if can't find any satisfiable data profile. */ public @Nullable DataProfile getDataProfileForNetworkRequest( @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, - boolean ignorePermanentFailure) { + boolean isNtn, boolean isEsimBootstrapProvisioning, boolean ignorePermanentFailure) { ApnSetting apnSetting = null; if (networkRequest.hasAttribute(TelephonyNetworkRequest .CAPABILITY_ATTRIBUTE_APN_SETTING)) { - apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, - ignorePermanentFailure); + apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, isNtn, + isEsimBootstrapProvisioning, ignorePermanentFailure); } TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder(); @@ -697,32 +723,60 @@ public class DataProfileManager extends Handler { * * @param networkRequest The network request. * @param networkType The current data network type. + * @param isNtn {@code true} if the device is currently attached to non-terrestrial network. * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}. * This should be set to true for condition-based retry/setup. * @return The APN setting. {@code null} if can't find any satisfiable data profile. */ private @Nullable ApnSetting getApnSettingForNetworkRequest( @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, - boolean ignorePermanentFailure) { + boolean isNtn, boolean isEsimBootStrapProvisioning, boolean ignorePermanentFailure) { if (!networkRequest.hasAttribute( TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) { loge("Network request does not have APN setting attribute."); return null; } - // If the preferred data profile can be used, always use it if it can satisfy the network - // request with current network type (even though it's been marked as permanent failed.) - if (mPreferredDataProfile != null - && networkRequest.canBeSatisfiedBy(mPreferredDataProfile) - && mPreferredDataProfile.getApnSetting() != null - && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)) { - if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting() - .getPermanentFailed()) { - return mPreferredDataProfile.getApnSetting(); + // if esim bootstrap provisioning in progress, do not apply preferred data profile + if (!isEsimBootStrapProvisioning) { + if (mFeatureFlags.carrierEnabledSatelliteFlag()) { + // If the preferred data profile can be used, always use it if it can satisfy the + // network request with current network type (even though it's been marked as + // permanent failed.) + if (mPreferredDataProfile != null + && networkRequest.canBeSatisfiedBy(mPreferredDataProfile) + && mPreferredDataProfile.getApnSetting() != null + && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType) + && ((isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure( + ApnSetting.INFRASTRUCTURE_SATELLITE)) + || (!isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure( + ApnSetting.INFRASTRUCTURE_CELLULAR)))) { + if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting() + .getPermanentFailed()) { + return mPreferredDataProfile.getApnSetting(); + } + log("The preferred data profile is permanently failed. Only condition based " + + "retry can happen."); + return null; + } + } else { + // If the preferred data profile can be used, always use it if it can satisfy the + // network request with current network type (even though it's been marked as + // permanent failed.) + if (mPreferredDataProfile != null + && networkRequest.canBeSatisfiedBy(mPreferredDataProfile) + && mPreferredDataProfile.getApnSetting() != null + && mPreferredDataProfile.getApnSetting() + .canSupportNetworkType(networkType)) { + if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting() + .getPermanentFailed()) { + return mPreferredDataProfile.getApnSetting(); + } + log("The preferred data profile is permanently failed. Only condition based " + + "retry can happen."); + return null; + } } - log("The preferred data profile is permanently failed. Only condition based retry " - + "can happen."); - return null; } // Filter out the data profile that can't satisfy the request. @@ -744,8 +798,24 @@ public class DataProfileManager extends Handler { // Check if the remaining data profiles can used in current data network type. dataProfiles = dataProfiles.stream() - .filter(dp -> dp.getApnSetting() != null - && dp.getApnSetting().canSupportNetworkType(networkType)) + .filter((dp) -> { + if (dp.getApnSetting() == null) return false; + if (!dp.getApnSetting().canSupportNetworkType(networkType)) return false; + if (isEsimBootStrapProvisioning + != dp.getApnSetting().isEsimBootstrapProvisioning()) return false; + if (mFeatureFlags.carrierEnabledSatelliteFlag()) { + if (isNtn && !dp.getApnSetting().isForInfrastructure( + ApnSetting.INFRASTRUCTURE_SATELLITE)) { + return false; + } + if (!isNtn && !dp.getApnSetting().isForInfrastructure( + ApnSetting.INFRASTRUCTURE_CELLULAR)) { + return false; + } + } + + return true; + }) .collect(Collectors.toList()); if (dataProfiles.size() == 0) { log("Can't find any data profile for network type " @@ -775,6 +845,10 @@ public class DataProfileManager extends Handler { return null; } + if (isEsimBootStrapProvisioning) { + log("Found esim bootstrap provisioning data profile for network request: " + + dataProfiles.get(0).getApnSetting()); + } return dataProfiles.get(0).getApnSetting(); } @@ -819,7 +893,10 @@ public class DataProfileManager extends Handler { new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .build(), mPhone); - return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null; + return getDataProfileForNetworkRequest(networkRequest, networkType, + mPhone.getServiceState().isUsingNonTerrestrialNetwork(), + mDataNetworkController.isEsimBootStrapProvisioningActivated(), + true) != null; } /** @@ -979,6 +1056,7 @@ public class DataProfileManager extends Handler { // The following fields in apn1 and apn2 should be the same, otherwise ApnSetting.similar() // should fail earlier. apnBuilder.setApnName(apn1.getApnName()); + apnBuilder.setOperatorNumeric(apn1.getOperatorNumeric()); apnBuilder.setProtocol(apn1.getProtocol()); apnBuilder.setRoamingProtocol(apn1.getRoamingProtocol()); apnBuilder.setCarrierEnabled(apn1.isEnabled()); @@ -993,6 +1071,8 @@ public class DataProfileManager extends Handler { apnBuilder.setCarrierId(apn1.getCarrierId()); apnBuilder.setSkip464Xlat(apn1.getSkip464Xlat()); apnBuilder.setAlwaysOn(apn1.isAlwaysOn()); + apnBuilder.setInfrastructureBitmask(apn1.getInfrastructureBitmask()); + apnBuilder.setEsimBootstrapProvisioning(apn1.isEsimBootstrapProvisioning()); return new DataProfile.Builder() .setApnSetting(apnBuilder.build()) diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 314668973b..5933463517 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -56,6 +56,7 @@ import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCa import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataProfileManager.DataProfileManagerCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -151,6 +152,9 @@ public class DataRetryManager extends Handler { /** The phone instance. */ private final @NonNull Phone mPhone; + /** Featureflags. */ + private final @NonNull FeatureFlags mFlags; + /** The RIL instance. */ private final @NonNull CommandsInterface mRil; @@ -962,10 +966,12 @@ public class DataRetryManager extends Handler { public DataRetryManager(@NonNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull SparseArray<DataServiceManager> dataServiceManagers, - @NonNull Looper looper, @NonNull DataRetryManagerCallback dataRetryManagerCallback) { + @NonNull Looper looper, @NonNull FeatureFlags flags, + @NonNull DataRetryManagerCallback dataRetryManagerCallback) { super(looper); mPhone = phone; mRil = phone.mCi; + mFlags = flags; mLogTag = "DRM-" + mPhone.getPhoneId(); mDataRetryManagerCallbacks.add(dataRetryManagerCallback); @@ -1018,18 +1024,21 @@ public class DataRetryManager extends Handler { mRil.registerForOn(this, EVENT_RADIO_ON, null); mRil.registerForModemReset(this, EVENT_MODEM_RESET, null); - // Register intent of alarm manager for long retry timer - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_RETRY); - mPhone.getContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (ACTION_RETRY.equals(intent.getAction())) { - DataRetryManager.this.onAlarmIntentRetry( - intent.getIntExtra(ACTION_RETRY_EXTRA_HASHCODE, -1 /*Bad hashcode*/)); + if (!mFlags.useAlarmCallback()) { + // Register intent of alarm manager for long retry timer + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_RETRY); + mPhone.getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_RETRY.equals(intent.getAction())) { + DataRetryManager.this.onAlarmIntentRetry( + intent.getIntExtra(ACTION_RETRY_EXTRA_HASHCODE, + -1 /*Bad hashcode*/)); + } } - } - }, intentFilter); + }, intentFilter); + } if (mDataConfigManager.shouldResetDataThrottlingWhenTacChanges()) { mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, EVENT_TAC_CHANGED, @@ -1450,8 +1459,7 @@ public class DataRetryManager extends Handler { * @param dataRetryEntry The data retry entry. */ private void schedule(@NonNull DataRetryEntry dataRetryEntry) { - logl("Scheduled data retry " + dataRetryEntry - + " hashcode=" + dataRetryEntry.hashCode()); + logl("Scheduled data retry " + dataRetryEntry + " hashcode=" + dataRetryEntry.hashCode()); mDataRetryEntries.add(dataRetryEntry); if (mDataRetryEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { // Discard the oldest retry entry. @@ -1467,16 +1475,32 @@ public class DataRetryManager extends Handler { ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry), dataRetryEntry.retryDelayMillis); } else { - Intent intent = new Intent(ACTION_RETRY); - intent.putExtra(ACTION_RETRY_EXTRA_HASHCODE, dataRetryEntry.hashCode()); - // No need to wake up the device, the retry can wait util next time the device wake up - // to save power. - mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, - dataRetryEntry.retryElapsedTime, - PendingIntent.getBroadcast(mPhone.getContext(), - dataRetryEntry.hashCode() /*Unique identifier of this retry attempt*/, - intent, - PendingIntent.FLAG_IMMUTABLE)); + if (mFlags.useAlarmCallback()) { + // No need to wake up the device, the retry can wait util next time the device wake + // up to save power. + mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, + dataRetryEntry.retryElapsedTime, + "dataRetryHash-" + dataRetryEntry.hashCode() /*debug tag*/, + Runnable::run, + null /*worksource*/, + () -> { + logl("onAlarm retry " + dataRetryEntry); + sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry + ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, + dataRetryEntry)); + }); + } else { + Intent intent = new Intent(ACTION_RETRY); + intent.putExtra(ACTION_RETRY_EXTRA_HASHCODE, dataRetryEntry.hashCode()); + // No need to wake up the device, the retry can wait util next time the device wake + // up to save power. + mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, + dataRetryEntry.retryElapsedTime, + PendingIntent.getBroadcast(mPhone.getContext(), + dataRetryEntry.hashCode()/*Unique identifier of the retry attempt*/, + intent, + PendingIntent.FLAG_IMMUTABLE)); + } } } @@ -1517,9 +1541,12 @@ public class DataRetryManager extends Handler { DataThrottlingEntry entry = new DataThrottlingEntry(dataProfile, networkRequestList, dataNetwork, transport, retryType, expirationTime); // Remove previous entry that contains the same data profile. Therefore it should always - // contain at maximum all the distinct data profiles of the current subscription. + // contain at maximu all the distinct data profiles of the current subscription times each + // transport. mDataThrottlingEntries.removeIf( - throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile)); + throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile) + && (!mFlags.unthrottleCheckTransport() + || throttlingEntry.transport == transport)); if (mDataThrottlingEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { // If we don't see the anomaly report after U release, we should remove this check for @@ -1581,7 +1608,8 @@ public class DataRetryManager extends Handler { // in DataProfileInfo.aidl), so we need to get the equivalent data profile from data // profile manager. Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream(); - stream = stream.filter(entry -> entry.expirationTimeMillis > now); + stream = stream.filter(entry -> entry.expirationTimeMillis > now + && (!mFlags.unthrottleCheckTransport() || entry.transport == transport)); if (dataProfile.getApnSetting() != null) { stream = stream .filter(entry -> entry.dataProfile.getApnSetting() != null) diff --git a/src/java/com/android/internal/telephony/data/DataServiceManager.java b/src/java/com/android/internal/telephony/data/DataServiceManager.java index bb0e8c3cb2..640399e6cc 100644 --- a/src/java/com/android/internal/telephony/data/DataServiceManager.java +++ b/src/java/com/android/internal/telephony/data/DataServiceManager.java @@ -55,6 +55,7 @@ import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.text.TextUtils; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.util.TelephonyUtils; @@ -947,6 +948,47 @@ public class DataServiceManager extends Handler { } /** + * Request data network validation. + * + * <p>Validates a given data network to ensure that the network can work properly. + * + * <p>Depending on the {@link DataServiceCallback.ResultCode}, Listener can determine whether + * validation has been triggered, has an error or whether it is a feature that is not supported. + * + * @param cid The identifier of the data network which is provided in DataCallResponse + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void requestValidation(int cid, @Nullable Message onCompleteMessage) { + if (DBG) log("requestValidation"); + if (!mBound) { + loge("DataService is not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + IIntegerConsumer callback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + mMessageMap.remove(asBinder()); + sendCompleteMessage(onCompleteMessage, result); + } + }; + if (onCompleteMessage != null) { + mMessageMap.put(callback.asBinder(), onCompleteMessage); + } + try { + mIDataService.requestValidation(mPhone.getPhoneId(), cid, callback); + } catch (RemoteException e) { + loge("Cannot invoke requestValidation on data service."); + if (callback != null) { + mMessageMap.remove(callback.asBinder()); + } + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** * Register for data service binding status changed event. * * @param h The target to post the event message to. diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index f8365bbef5..e54f6d382e 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -28,6 +28,7 @@ import android.preference.PreferenceManager; import android.provider.Settings; import android.sysprop.TelephonyProperties; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.MobileDataPolicy; @@ -208,7 +209,9 @@ public class DataSettingsManager extends Handler { case EVENT_SUBSCRIPTIONS_CHANGED: { mSubId = (int) msg.obj; refreshEnabledMobileDataPolicy(); - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER, + mPhone.getContext().getOpPackageName(), + SubscriptionManager.isValidSubscriptionId(mSubId)); mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); break; } @@ -342,15 +345,15 @@ public class DataSettingsManager extends Handler { } private void updateDataEnabledAndNotify(@TelephonyManager.DataEnabledChangedReason int reason) { - updateDataEnabledAndNotify(reason, mPhone.getContext().getOpPackageName()); + updateDataEnabledAndNotify(reason, mPhone.getContext().getOpPackageName(), false); } private void updateDataEnabledAndNotify(@TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { + @NonNull String callingPackage, boolean shouldNotify) { boolean prevDataEnabled = mIsDataEnabled; mIsDataEnabled = isDataEnabled(ApnSetting.TYPE_ALL); log("mIsDataEnabled=" + mIsDataEnabled + ", prevDataEnabled=" + prevDataEnabled); - if (!mInitialized || prevDataEnabled != mIsDataEnabled) { + if (!mInitialized || shouldNotify || prevDataEnabled != mIsDataEnabled) { if (!mInitialized) mInitialized = true; notifyDataEnabledChanged(mIsDataEnabled, reason, callingPackage); } @@ -443,7 +446,8 @@ public class DataSettingsManager extends Handler { mPhone.notifyUserMobileDataStateChanged(enabled); mDataSettingsManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onUserDataEnabledChanged(enabled, callingPackage))); - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER, callingPackage); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER, + callingPackage, false); } } @@ -474,7 +478,8 @@ public class DataSettingsManager extends Handler { if (mDataEnabledSettings.get(TelephonyManager.DATA_ENABLED_REASON_POLICY) != enabled) { logl("PolicyDataEnabled changed to " + enabled + ", callingPackage=" + callingPackage); mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_POLICY, enabled); - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_POLICY, callingPackage); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_POLICY, + callingPackage, false); } } @@ -488,7 +493,7 @@ public class DataSettingsManager extends Handler { logl("CarrierDataEnabled changed to " + enabled + ", callingPackage=" + callingPackage); mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled); updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_CARRIER, - callingPackage); + callingPackage, false); } } @@ -502,7 +507,7 @@ public class DataSettingsManager extends Handler { logl("ThermalDataEnabled changed to " + enabled + ", callingPackage=" + callingPackage); mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_THERMAL, enabled); updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_THERMAL, - callingPackage); + callingPackage, false); } } @@ -750,23 +755,22 @@ public class DataSettingsManager extends Handler { boolean isNonDds = mPhone.getSubId() != SubscriptionManagerService.getInstance() .getDefaultDataSubId(); + Phone defaultDataPhone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() + .getPhoneId(SubscriptionManagerService.getInstance() + .getDefaultDataSubId())); + boolean isDdsUserEnabled = defaultDataPhone != null && defaultDataPhone.isUserDataEnabled(); + // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL)) { - overridden = overridden || isNonDds && mPhone.getState() != PhoneConstants.State.IDLE; + overridden |= isNonDds && isDdsUserEnabled + && mPhone.getState() != PhoneConstants.State.IDLE; } // mobile data policy : auto data switch if (isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) { // check user enabled data on the default data phone - Phone defaultDataPhone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() - .getPhoneId(SubscriptionManagerService.getInstance() - .getDefaultDataSubId())); - if (defaultDataPhone == null) { - loge("isDataEnabledOverriddenForApn: unexpected defaultDataPhone is null"); - } else { - overridden = overridden || isNonDds && defaultDataPhone.isUserDataEnabled(); - } + overridden |= isNonDds && isDdsUserEnabled; } return overridden; } diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index 375b2503a7..f2b677692b 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.content.Intent; import android.database.ContentObserver; import android.net.NetworkAgent; +import android.net.NetworkCapabilities; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -56,7 +57,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; -import java.util.List; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -191,7 +192,7 @@ public class DataStallRecoveryManager extends Handler { private boolean mMobileDataChangedToEnabledDuringDataStall; /** Whether attempted all recovery steps. */ private boolean mIsAttemptedAllSteps; - /** Whether internet network connected. */ + /** Whether internet network that require validation is connected. */ private boolean mIsInternetNetworkConnected; /** The durations for current recovery action */ private @ElapsedRealtimeLong long mTimeElapsedOfCurrentAction; @@ -307,16 +308,26 @@ public class DataStallRecoveryManager extends Handler { } @Override - public void onInternetDataNetworkConnected( - @NonNull List<DataNetwork> internetNetworks) { - mIsInternetNetworkConnected = true; - logl("onInternetDataNetworkConnected"); - } - - @Override - public void onInternetDataNetworkDisconnected() { - mIsInternetNetworkConnected = false; - logl("onInternetDataNetworkDisconnected"); + public void onConnectedInternetDataNetworksChanged( + @NonNull Set<DataNetwork> internetNetworks) { + boolean anyInternetRequireValidatedConnected = internetNetworks.stream() + .anyMatch(nw -> { + NetworkCapabilities capabilities = nw.getNetworkCapabilities(); + // Only track the networks that require validation. + // The criteria is base on NetworkMonitorUtils.java. + return capabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && capabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED) + && capabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VPN); + }); + if (mIsInternetNetworkConnected != anyInternetRequireValidatedConnected) { + mIsInternetNetworkConnected = anyInternetRequireValidatedConnected; + logl(mIsInternetNetworkConnected + ? "At Least One InternetDataNetwork Connected" + : "All InternetDataNetwork Disconnected"); + } } }); mPhone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java index fc0c4f1145..259b482c01 100644 --- a/src/java/com/android/internal/telephony/data/DataUtils.java +++ b/src/java/com/android/internal/telephony/data/DataUtils.java @@ -90,6 +90,8 @@ public class DataUtils { return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH; case "PRIORITIZE_LATENCY": return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY; + case "RCS": + return NetworkCapabilities.NET_CAPABILITY_RCS; default: return -1; } @@ -254,6 +256,8 @@ public class DataUtils { return ApnSetting.TYPE_VSIM; case NetworkCapabilities.NET_CAPABILITY_BIP: return ApnSetting.TYPE_BIP; + case NetworkCapabilities.NET_CAPABILITY_RCS: + return ApnSetting.TYPE_RCS; default: return ApnSetting.TYPE_NONE; } @@ -295,6 +299,8 @@ public class DataUtils { return NetworkCapabilities.NET_CAPABILITY_VSIM; case ApnSetting.TYPE_ENTERPRISE: return NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; + case ApnSetting.TYPE_RCS: + return NetworkCapabilities.NET_CAPABILITY_RCS; default: return -1; } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 13ccadcabe..8dc8098aed 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -84,6 +84,7 @@ import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; @@ -185,6 +186,7 @@ public class PhoneSwitcher extends Handler { private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; private final SubscriptionManagerService mSubscriptionManagerService; + private final @NonNull FeatureFlags mFlags; protected final Context mContext; private final LocalLog mLocalLog; protected PhoneState[] mPhoneStates; @@ -195,8 +197,6 @@ public class PhoneSwitcher extends Handler { private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; /** The reason for the last time changing preferred data sub **/ private int mLastSwitchPreferredDataReason = -1; - /** {@code true} if we've displayed the notification the first time auto switch occurs **/ - private boolean mDisplayedAutoSwitchNotification = false; private boolean mPendingSwitchNeedValidation; @VisibleForTesting public final CellularNetworkValidator.ValidationCallback mValidationCallback = @@ -313,15 +313,17 @@ public class PhoneSwitcher extends Handler { // Default timeout value of network validation in millisecond. private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000; + /** Controller that tracks {@link TelephonyManager#MOBILE_DATA_POLICY_AUTO_DATA_SWITCH} */ + @NonNull private final AutoDataSwitchController mAutoDataSwitchController; + /** Callback to deal with requests made by the auto data switch controller. */ + @NonNull private final AutoDataSwitchController.AutoDataSwitchControllerCallback + mAutoDataSwitchCallback; + private ConnectivityManager mConnectivityManager; private int mImsRegistrationTech = REGISTRATION_TECH_NONE; private List<Set<CommandException.Error>> mCurrentDdsSwitchFailure; - private AutoDataSwitchController mAutoDataSwitchController; - private AutoDataSwitchController.AutoDataSwitchControllerCallback - mAutoDataSwitchCallback; - /** Data settings manager callback. Key is the phone id. */ private final @NonNull Map<Integer, DataSettingsManagerCallback> mDataSettingsManagerCallbacks = new ArrayMap<>(); @@ -398,9 +400,10 @@ public class PhoneSwitcher extends Handler { /** * Method to create singleton instance. */ - public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) { + public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper, + @NonNull FeatureFlags flags) { if (sPhoneSwitcher == null) { - sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper); + sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper, flags); } return sPhoneSwitcher; @@ -458,9 +461,11 @@ public class PhoneSwitcher extends Handler { } @VisibleForTesting - public PhoneSwitcher(int maxActivePhones, Context context, Looper looper) { + public PhoneSwitcher(int maxActivePhones, Context context, Looper looper, + @NonNull FeatureFlags featureFlags) { super(looper); mContext = context; + mFlags = featureFlags; mActiveModemCount = getTm().getActiveModemCount(); mPhoneSubscriptions = new int[mActiveModemCount]; mPhoneStates = new PhoneState[mActiveModemCount]; @@ -498,6 +503,12 @@ public class PhoneSwitcher extends Handler { @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { PhoneSwitcher.this.onDataEnabledChanged(); + } + @Override + public void onDataRoamingEnabledChanged(boolean enabled) { + PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch( + AutoDataSwitchController + .EVALUATION_REASON_DATA_SETTINGS_CHANGED); }}); phone.getDataSettingsManager().registerCallback( mDataSettingsManagerCallbacks.get(phoneId)); @@ -514,7 +525,7 @@ public class PhoneSwitcher extends Handler { TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); telephonyRegistryManager.addOnSubscriptionsChangedListener( - mSubscriptionsChangedListener, mSubscriptionsChangedListener.getHandlerExecutor()); + mSubscriptionsChangedListener, this::post); mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); @@ -547,7 +558,7 @@ public class PhoneSwitcher extends Handler { } }; mAutoDataSwitchController = new AutoDataSwitchController(context, looper, this, - mAutoDataSwitchCallback); + mFlags, mAutoDataSwitchCallback); mContext.registerReceiver(mDefaultDataChangedReceiver, new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); @@ -902,6 +913,12 @@ public class PhoneSwitcher extends Handler { @NonNull String callingPackage) { PhoneSwitcher.this.onDataEnabledChanged(); } + @Override + public void onDataRoamingEnabledChanged(boolean enabled) { + PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch( + AutoDataSwitchController + .EVALUATION_REASON_DATA_SETTINGS_CHANGED); + } }); phone.getDataSettingsManager().registerCallback( mDataSettingsManagerCallbacks.get(phone.getPhoneId())); @@ -1080,6 +1097,7 @@ public class PhoneSwitcher extends Handler { registerForImsRadioTechChange(mContext, i); } diffDetected = true; + mAutoDataSwitchController.notifySubscriptionsMappingChanged(); } } @@ -1388,7 +1406,7 @@ public class PhoneSwitcher extends Handler { return defaultDataPhone != null // check user enabled data && defaultDataPhone.isUserDataEnabled() && voicePhone != null // check user enabled voice during call feature - && voicePhone.isDataAllowed(); + && voicePhone.getDataSettingsManager().isDataEnabled(); } protected void transitionToEmergencyPhone() { @@ -1843,7 +1861,6 @@ public class PhoneSwitcher extends Handler { pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure); pw.println("mLastSwitchPreferredDataReason=" + switchReasonToString(mLastSwitchPreferredDataReason)); - pw.println("mDisplayedAutoSwitchNotification=" + mDisplayedAutoSwitchNotification); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java index b334b89d75..26683020a0 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java @@ -130,7 +130,9 @@ public class TelephonyNetworkRequest { new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY, CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH, - CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID) + CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), + new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_RCS, + CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN) ); /** The phone instance. */ diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java index 9a75b43aa4..f5cf9501d2 100644 --- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java @@ -21,10 +21,13 @@ import android.annotation.Nullable; import android.os.AsyncResult; import android.os.CancellationSignal; import android.os.Handler; -import android.os.HandlerThread; import android.os.Looper; import android.os.Message; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.Annotation.ApnType; import android.telephony.Annotation.DisconnectCauses; import android.telephony.DomainSelectionService; import android.telephony.DomainSelectionService.EmergencyScanType; @@ -33,19 +36,19 @@ import android.telephony.EmergencyRegResult; import android.telephony.NetworkRegistrationInfo; import android.telephony.TransportSelectorCallback; import android.telephony.WwanSelectorCallback; +import android.telephony.data.ApnSetting; import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import com.android.internal.telephony.util.TelephonyUtils; import java.io.PrintWriter; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -74,42 +77,63 @@ public class DomainSelectionConnection { private final class TransportSelectorCallbackWrapper implements TransportSelectorCallback { @Override public void onCreated(@NonNull DomainSelector selector) { - mDomainSelector = selector; - DomainSelectionConnection.this.onCreated(); + synchronized (mLock) { + mDomainSelector = selector; + if (mDisposed) { + mDomainSelector.cancelSelection(); + return; + } + DomainSelectionConnection.this.onCreated(); + } } @Override public void onWlanSelected(boolean useEmergencyPdn) { - DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn); + synchronized (mLock) { + if (mDisposed) return; + DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn); + } } @Override public @NonNull WwanSelectorCallback onWwanSelected() { - if (mWwanSelectorCallback == null) { - mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + synchronized (mLock) { + if (mWwanSelectorCallback == null) { + mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + } + if (mDisposed) { + return mWwanSelectorCallback; + } + DomainSelectionConnection.this.onWwanSelected(); + return mWwanSelectorCallback; } - DomainSelectionConnection.this.onWwanSelected(); - return mWwanSelectorCallback; } @Override public void onWwanSelected(final Consumer<WwanSelectorCallback> consumer) { - if (mWwanSelectorCallback == null) { - mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + synchronized (mLock) { + if (mDisposed) return; + if (mWwanSelectorCallback == null) { + mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + } + initHandler(); + mHandler.post(() -> { + synchronized (mLock) { + if (mDisposed) return; + DomainSelectionConnection.this.onWwanSelected(); + consumer.accept(mWwanSelectorCallback); + } + }); } - if (mWwanSelectedExecutor == null) { - mWwanSelectedExecutor = Executors.newSingleThreadExecutor(); - } - mWwanSelectedExecutor.execute(() -> { - DomainSelectionConnection.this.onWwanSelected(); - consumer.accept(mWwanSelectorCallback); - }); } @Override public void onSelectionTerminated(int cause) { - DomainSelectionConnection.this.onSelectionTerminated(cause); - dispose(); + synchronized (mLock) { + if (mDisposed) return; + DomainSelectionConnection.this.onSelectionTerminated(cause); + dispose(); + } } } @@ -120,22 +144,38 @@ public class DomainSelectionConnection { public void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks, @EmergencyScanType int scanType, @NonNull CancellationSignal signal, @NonNull Consumer<EmergencyRegResult> consumer) { - if (signal != null) signal.setOnCancelListener(this); - mResultCallback = consumer; - initHandler(); - DomainSelectionConnection.this.onRequestEmergencyNetworkScan( - preferredNetworks.stream().mapToInt(Integer::intValue).toArray(), scanType); + synchronized (mLock) { + if (mDisposed) return; + if (signal != null) signal.setOnCancelListener(this); + mResultCallback = consumer; + initHandler(); + mHandler.post(() -> { + synchronized (mLock) { + DomainSelectionConnection.this.onRequestEmergencyNetworkScan( + preferredNetworks.stream().mapToInt(Integer::intValue).toArray(), + scanType); + } + }); + } } @Override public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, boolean useEmergencyPdn) { - DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn); + synchronized (mLock) { + if (mDisposed) return; + DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn); + } } @Override public void onCancel() { - DomainSelectionConnection.this.onCancel(); + synchronized (mLock) { + if (mDisposed || mHandler == null) return; + mHandler.post(() -> { + DomainSelectionConnection.this.onCancel(); + }); + } } } @@ -156,10 +196,15 @@ public class DomainSelectionConnection { if (DBG) logd("EVENT_EMERGENCY_NETWORK_SCAN_RESULT result=" + regResult); CompletableFuture.runAsync( () -> mResultCallback.accept(regResult), - mController.getDomainSelectionServiceExecutor()).join(); + mController.getDomainSelectionServiceExecutor()); break; case EVENT_QUALIFIED_NETWORKS_CHANGED: - onQualifiedNetworksChanged(); + ar = (AsyncResult) msg.obj; + if (ar == null || ar.result == null) { + loge("handleMessage EVENT_QUALIFIED_NETWORKS_CHANGED null result"); + break; + } + onQualifiedNetworksChanged((List<QualifiedNetworks>) ar.result); break; default: loge("handleMessage unexpected msg=" + msg.what); @@ -170,6 +215,8 @@ public class DomainSelectionConnection { protected String mTag = "DomainSelectionConnection"; + private boolean mDisposed = false; + private final Object mLock = new Object(); private final LocalLog mLocalLog = new LocalLog(30); private final @NonNull TransportSelectorCallback mTransportSelectorCallback; @@ -196,15 +243,13 @@ public class DomainSelectionConnection { /** The attributes required to determine the domain. */ private @Nullable DomainSelectionService.SelectionAttributes mSelectionAttributes; - private @Nullable Looper mLooper; + private final @NonNull Looper mLooper; protected @Nullable DomainSelectionConnectionHandler mHandler; private boolean mRegisteredRegistrant; private boolean mIsWaitingForScanResult; private @NonNull AndroidFuture<Integer> mOnComplete; - private @Nullable Executor mWwanSelectedExecutor; - /** * Creates an instance. * @@ -220,6 +265,7 @@ public class DomainSelectionConnection { mPhone = phone; mSelectorType = selectorType; mIsEmergency = isEmergency; + mLooper = Looper.getMainLooper(); mTransportSelectorCallback = new TransportSelectorCallbackWrapper(); mOnComplete = new AndroidFuture<>(); @@ -323,6 +369,8 @@ public class DomainSelectionConnection { public void onRequestEmergencyNetworkScan( @NonNull @RadioAccessNetworkType int[] preferredNetworks, @EmergencyScanType int scanType) { + if (mHandler == null) return; + // Can be overridden if required if (!mRegisteredRegistrant) { mPhone.registerForEmergencyNetworkScan(mHandler, @@ -376,9 +424,12 @@ public class DomainSelectionConnection { * to clean up all ongoing operations with the framework. */ public void cancelSelection() { - if (mDomainSelector == null) return; - mDomainSelector.cancelSelection(); - dispose(); + synchronized (mLock) { + if (mDomainSelector != null) { + mDomainSelector.cancelSelection(); + } + dispose(); + } } /** @@ -400,9 +451,12 @@ public class DomainSelectionConnection { * Finishes the selection procedure and cleans everything up. */ public void finishSelection() { - if (mDomainSelector == null) return; - mDomainSelector.finishSelection(); - dispose(); + synchronized (mLock) { + if (mDomainSelector != null) { + mDomainSelector.finishSelection(); + } + dispose(); + } } /** Indicates that the service connection has been removed. */ @@ -412,30 +466,25 @@ public class DomainSelectionConnection { } private void dispose() { + mDisposed = true; if (mRegisteredRegistrant) { mPhone.unregisterForEmergencyNetworkScan(mHandler); mRegisteredRegistrant = false; } onCancel(true); mController.removeConnection(this); - if (mLooper != null) mLooper.quitSafely(); - mLooper = null; + if (mHandler != null) mHandler.removeCallbacksAndMessages(null); mHandler = null; } protected void initHandler() { - if (mLooper == null) { - HandlerThread handlerThread = new HandlerThread(mTag); - handlerThread.start(); - mLooper = handlerThread.getLooper(); - } if (mHandler == null) mHandler = new DomainSelectionConnectionHandler(mLooper); } /** * Notifies the change of qualified networks. */ - protected void onQualifiedNetworksChanged() { + protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) { if (mIsEmergency && (mSelectorType == DomainSelectionService.SELECTOR_TYPE_CALLING)) { // DomainSelectionConnection for emergency calls shall override this. @@ -445,6 +494,33 @@ public class DomainSelectionConnection { } /** + * Get the preferred transport. + * + * @param apnType APN type. + * @return The preferred transport. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) + public int getPreferredTransport(@ApnType int apnType, + List<QualifiedNetworks> networksList) { + for (QualifiedNetworks networks : networksList) { + if (networks.qualifiedNetworks.length > 0) { + if (networks.apnType == apnType) { + return getTransportFromAccessNetwork(networks.qualifiedNetworks[0]); + } + } + } + + loge("getPreferredTransport no network found for " + ApnSetting.getApnTypeString(apnType)); + return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + } + + private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { + return accessNetwork == AccessNetworkType.IWLAN + ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN + : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + } + + /** * Dumps local log. */ public void dump(@NonNull PrintWriter printWriter) { diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java index cbb74fadd7..65ac8b3ca7 100644 --- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java @@ -150,9 +150,14 @@ public class DomainSelectionResolver { throw new IllegalStateException("DomainSelection is not supported!"); } - if (phone == null || !phone.isImsAvailable()) { - // If ImsPhone is null or the binder of ImsService is not available, - // CS domain is used for the telephony services. + if (phone == null || phone.getImsPhone() == null + || (!(isEmergency && selectorType == DomainSelectionService.SELECTOR_TYPE_CALLING) + && !phone.isImsAvailable())) { + // In case of emergency calls, to recover the temporary failure in IMS service + // connection, DomainSelection shall be started even when IMS isn't available. + // DomainSelector will keep finding next available transport. + // For other telephony services, if the binder of ImsService is not available, + // CS domain will be used. return null; } diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 5f3c3b69e9..c39778875d 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -40,8 +40,10 @@ import android.telephony.ims.ImsReasonInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import java.util.List; import java.util.concurrent.CompletableFuture; /** @@ -163,9 +165,8 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne /** {@inheritDoc} */ @Override - protected void onQualifiedNetworksChanged() { - AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - int preferredTransport = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) { + int preferredTransport = getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList); logi("onQualifiedNetworksChanged preferred=" + mPreferredTransportType + ", current=" + preferredTransport); if (preferredTransport == mPreferredTransportType) { @@ -177,6 +178,7 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne future.complete(DOMAIN_PS); } } + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); anm.unregisterForQualifiedNetworksChanged(mHandler); } } diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java index efcdf116e4..b776e21b7b 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java @@ -28,8 +28,11 @@ import android.telephony.data.ApnSetting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import java.util.List; + /** * Manages the information of request and the callback binder for an emergency SMS. */ @@ -139,14 +142,14 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon } @Override - protected void onQualifiedNetworksChanged() { - AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - int preferredTransportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + protected void onQualifiedNetworksChanged(List<QualifiedNetworks> networksList) { + int preferredTransportType = getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList); synchronized (mLock) { if (preferredTransportType == mPreferredTransportType) { mPreferredTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); anm.unregisterForQualifiedNetworksChanged(mHandler); } } diff --git a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java index e157d24f37..0532a05d41 100644 --- a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java @@ -22,9 +22,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; import android.telephony.Annotation.DisconnectCauses; +import android.telephony.DisconnectCause; import android.telephony.DomainSelectionService; import android.telephony.DomainSelectionService.EmergencyScanType; import android.telephony.NetworkRegistrationInfo; +import android.telephony.PreciseDisconnectCause; import android.telephony.ims.ImsReasonInfo; import com.android.internal.telephony.Phone; @@ -37,15 +39,9 @@ import java.util.concurrent.CompletableFuture; public class NormalCallDomainSelectionConnection extends DomainSelectionConnection { private static final boolean DBG = false; - - private static final String PREFIX_WPS = "*272"; - - // WPS prefix when CLIR is being activated for the call. - private static final String PREFIX_WPS_CLIR_ACTIVATE = "*31#*272"; - - // WPS prefix when CLIR is being deactivated for the call. - private static final String PREFIX_WPS_CLIR_DEACTIVATE = "#31#*272"; - + private int mDisconnectCause = DisconnectCause.NOT_VALID; + private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID; + private String mReasonMessage = null; private @Nullable DomainSelectionConnectionCallback mCallback; @@ -134,13 +130,47 @@ public class NormalCallDomainSelectionConnection extends DomainSelectionConnecti } /** - * Check if the call is Wireless Priority Service call - * @param dialString The number being dialed. - * @return {@code true} if dialString matches WPS pattern and {@code false} otherwise. + * Save call disconnect info for error propagation. + * @param disconnectCause The code for the reason for the disconnect. + * @param preciseDisconnectCause The code for the precise reason for the disconnect. + * @param reasonMessage Description of the reason for the disconnect, not intended for the user + * to see. + */ + public void setDisconnectCause(int disconnectCause, int preciseDisconnectCause, + String reasonMessage) { + mDisconnectCause = disconnectCause; + mPreciseDisconnectCause = preciseDisconnectCause; + mReasonMessage = reasonMessage; + } + + public int getDisconnectCause() { + return mDisconnectCause; + } + + public int getPreciseDisconnectCause() { + return mPreciseDisconnectCause; + } + + public String getReasonMessage() { + return mReasonMessage; + } + + /** + * @return imsReasonInfo Reason for the IMS call failure. + */ + public @Nullable ImsReasonInfo getImsReasonInfo() { + if (getSelectionAttributes() == null) { + // Neither selectDomain(...) nor reselectDomain(...) has been called yet. + return null; + } + + return getSelectionAttributes().getPsDisconnectCause(); + } + + /** + * @return phoneId To support localized message based on phoneId */ - public static boolean isWpsCall(String dialString) { - return (dialString != null) && (dialString.startsWith(PREFIX_WPS) - || dialString.startsWith(PREFIX_WPS_CLIR_ACTIVATE) - || dialString.startsWith(PREFIX_WPS_CLIR_DEACTIVATE)); + public int getPhoneId() { + return getPhone().getPhoneId(); } } diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index 96cd880882..0692f7d3bd 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.emergency; +import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL; + import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; @@ -26,6 +28,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -33,17 +36,21 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.UserHandle; +import android.preference.PreferenceManager; import android.provider.Settings; import android.sysprop.TelephonyProperties; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DisconnectCauses; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; import android.telephony.NetworkRegistrationInfo; +import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; -import android.telephony.emergency.EmergencyNumber; +import android.telephony.data.ApnSetting; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; @@ -54,6 +61,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.PhoneSwitcher; +import com.android.internal.telephony.satellite.SatelliteController; import com.android.telephony.Rlog; import java.lang.annotation.Retention; @@ -62,6 +70,7 @@ import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -80,6 +89,7 @@ public class EmergencyStateTracker { private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true; /** Default Emergency Callback Mode exit timeout value. */ private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000; + private static final int DEFAULT_EPDN_DISCONNECTION_TIMEOUT_MS = 500; /** The emergency types used when setting the emergency mode on modem. */ @Retention(RetentionPolicy.SOURCE) @@ -94,6 +104,8 @@ public class EmergencyStateTracker { /** Indicates the emergency type is SMS. */ public static final int EMERGENCY_TYPE_SMS = 2; + private static final String KEY_NO_SIM_ECBM_SUPPORT = "no_sim_ecbm_support"; + private static EmergencyStateTracker INSTANCE = null; private final Context mContext; @@ -115,6 +127,9 @@ public class EmergencyStateTracker { private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode; // Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}. private final Set<String> mActiveEmergencyCalls = new ArraySet<>(); + private Phone mPhoneToExit; + private int mPdnDisconnectionTimeoutMs = DEFAULT_EPDN_DISCONNECTION_TIMEOUT_MS; + private final Object mLock = new Object(); private Phone mPhone; // Tracks ongoing emergency callId to handle a second emergency call private String mOngoingCallId; @@ -125,6 +140,7 @@ public class EmergencyStateTracker { private boolean mIsInEcm; private boolean mIsTestEmergencyNumber; private Runnable mOnEcmExitCompleteRunnable; + private int mOngoingCallProperties; /** For emergency SMS */ private final Set<String> mOngoingEmergencySmsIds = new ArraySet<>(); @@ -132,6 +148,12 @@ public class EmergencyStateTracker { private CompletableFuture<Integer> mSmsEmergencyModeFuture; private boolean mIsTestEmergencyNumberForSms; + private final android.util.ArrayMap<Integer, Boolean> mNoSimEcbmSupported = + new android.util.ArrayMap<>(); + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged( + slotIndex, subId); + /** * Listens for Emergency Callback Mode state change intents */ @@ -153,6 +175,29 @@ public class EmergencyStateTracker { } }; + /** + * TelephonyCallback used to monitor whether ePDN on cellular network is disconnected or not. + */ + private final class PreciseDataConnectionStateListener extends TelephonyCallback implements + TelephonyCallback.PreciseDataConnectionStateListener { + @Override + public void onPreciseDataConnectionStateChanged( + @NonNull PreciseDataConnectionState dataConnectionState) { + ApnSetting apnSetting = dataConnectionState.getApnSetting(); + if ((apnSetting == null) + || ((apnSetting.getApnTypeBitmask() | ApnSetting.TYPE_EMERGENCY) == 0) + || (dataConnectionState.getTransportType() + != AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) { + return; + } + int state = dataConnectionState.getState(); + Rlog.d(TAG, "onPreciseDataConnectionStateChanged ePDN state=" + state); + if (state == TelephonyManager.DATA_DISCONNECTED) exitEmergencyModeIfDelayed(); + } + } + + private PreciseDataConnectionStateListener mDataConnectionStateListener; + /** PhoneFactory Dependencies for testing. */ @VisibleForTesting public interface PhoneFactoryProxy { @@ -176,6 +221,8 @@ public class EmergencyStateTracker { @VisibleForTesting public interface TelephonyManagerProxy { int getPhoneCount(); + void registerTelephonyCallback(int subId, Executor executor, TelephonyCallback callback); + void unregisterTelephonyCallback(TelephonyCallback callback); } private final TelephonyManagerProxy mTelephonyManagerProxy; @@ -183,7 +230,6 @@ public class EmergencyStateTracker { private static class TelephonyManagerProxyImpl implements TelephonyManagerProxy { private final TelephonyManager mTelephonyManager; - TelephonyManagerProxyImpl(Context context) { mTelephonyManager = new TelephonyManager(context); } @@ -192,6 +238,18 @@ public class EmergencyStateTracker { public int getPhoneCount() { return mTelephonyManager.getActiveModemCount(); } + + @Override + public void registerTelephonyCallback(int subId, + Executor executor, TelephonyCallback callback) { + TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId); + tm.registerTelephonyCallback(executor, callback); + } + + @Override + public void unregisterTelephonyCallback(TelephonyCallback callback) { + mTelephonyManager.unregisterTelephonyCallback(callback); + } } /** @@ -203,11 +261,15 @@ public class EmergencyStateTracker { } @VisibleForTesting - public static final int MSG_SET_EMERGENCY_MODE_DONE = 1; + public static final int MSG_SET_EMERGENCY_MODE = 1; + @VisibleForTesting + public static final int MSG_EXIT_EMERGENCY_MODE = 2; + @VisibleForTesting + public static final int MSG_SET_EMERGENCY_MODE_DONE = 3; @VisibleForTesting - public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 2; + public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 4; @VisibleForTesting - public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 3; + public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 5; private class MyHandler extends Handler { @@ -251,7 +313,7 @@ public class EmergencyStateTracker { if (mIsEmergencyCallStartedDuringEmergencySms) { Phone phone = mPhone; mPhone = null; - exitEmergencyMode(mSmsPhone, emergencyType); + exitEmergencyMode(mSmsPhone, emergencyType, false); // Restore call phone for further use. mPhone = phone; @@ -310,6 +372,27 @@ public class EmergencyStateTracker { } break; } + case MSG_EXIT_EMERGENCY_MODE: { + Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE"); + exitEmergencyModeIfDelayed(); + break; + } + case MSG_SET_EMERGENCY_MODE: { + AsyncResult ar = (AsyncResult) msg.obj; + Integer emergencyType = (Integer) ar.userObj; + Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE for " + + emergencyTypeToString(emergencyType) + ", " + mEmergencyMode); + // Should be reached here only when starting a new emergency service + // while exiting emergency callback mode on the other slot. + if (mEmergencyMode != MODE_EMERGENCY_WWAN) return; + final Phone phone = (mPhone != null) ? mPhone : mSmsPhone; + if (phone != null) { + mWasEmergencyModeSetOnModem = true; + phone.setEmergencyMode(MODE_EMERGENCY_WWAN, + mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE, emergencyType)); + } + break; + } default: break; } @@ -356,6 +439,13 @@ public class EmergencyStateTracker { mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "telephony:" + TAG) : null; mConfigManager = context.getSystemService(CarrierConfigManager.class); + if (mConfigManager != null) { + // Carrier config changed callback should be executed in handler thread + mConfigManager.registerCarrierConfigChangeListener(mHandler::post, + mCarrierConfigChangeListener); + } else { + Rlog.e(TAG, "CarrierConfigLoader is not available."); + } // Register receiver for ECM exit. IntentFilter filter = new IntentFilter(); @@ -392,6 +482,8 @@ public class EmergencyStateTracker { mEcmExitTimeoutMs = ecmExitTimeoutMs; mWakeLock = null; // Don't declare a wakelock in tests mConfigManager = context.getSystemService(CarrierConfigManager.class); + mConfigManager.registerCarrierConfigChangeListener(mHandler::post, + mCarrierConfigChangeListener); IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); context.registerReceiver(mEcmExitReceiver, filter, null, mHandler); @@ -427,6 +519,7 @@ public class EmergencyStateTracker { return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED); } + mOngoingCallProperties = 0; mCallEmergencyModeFuture = new CompletableFuture<>(); if (mSmsPhone != null) { @@ -437,7 +530,7 @@ public class EmergencyStateTracker { // exit the emergency mode when receiving the result of setting the emergency mode and // the emergency mode for this call will be restarted after the exit complete. if (isInEmergencyMode() && !isEmergencyModeInProgress()) { - exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS); + exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, false); } mPhone = phone; @@ -467,6 +560,7 @@ public class EmergencyStateTracker { if (Objects.equals(mOngoingCallId, callId)) { mOngoingCallId = null; + mOngoingCallProperties = 0; } if (wasActive && mActiveEmergencyCalls.isEmpty() @@ -488,7 +582,7 @@ public class EmergencyStateTracker { MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); } } else { - exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL); + exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, false); clearEmergencyCallInfo(); } } @@ -500,6 +594,7 @@ public class EmergencyStateTracker { mIsEmergencyCallStartedDuringEmergencySms = false; mCallEmergencyModeFuture = null; mOngoingCallId = null; + mOngoingCallProperties = 0; mPhone = null; } @@ -552,8 +647,27 @@ public class EmergencyStateTracker { return; } - mWasEmergencyModeSetOnModem = true; - phone.setEmergencyMode(mode, m); + synchronized (mLock) { + unregisterForDataConnectionStateChanges(); + if (mPhoneToExit != null) { + if (emergencyType != EMERGENCY_TYPE_CALL) { + setIsInEmergencyCall(false); + } + mOnEcmExitCompleteRunnable = null; + if (mPhoneToExit != phone) { + // Exit emergency mode on the other phone first, + // then set emergency mode on the given phone. + mPhoneToExit.exitEmergencyMode( + mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE, + Integer.valueOf(emergencyType))); + mPhoneToExit = null; + return; + } + mPhoneToExit = null; + } + mWasEmergencyModeSetOnModem = true; + phone.setEmergencyMode(mode, m); + } } private void completeEmergencyMode(@EmergencyType int emergencyType) { @@ -626,8 +740,10 @@ public class EmergencyStateTracker { * * @param phone the {@code Phone} to exit the emergency mode. * @param emergencyType the emergency type to identify an emergency call or SMS. + * @param waitForPdnDisconnect indicates whether it shall wait for the disconnection of ePDN. */ - private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType) { + private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType, + boolean waitForPdnDisconnect) { Rlog.i(TAG, "exitEmergencyMode for " + emergencyTypeToString(emergencyType)); if (emergencyType == EMERGENCY_TYPE_CALL) { @@ -663,8 +779,23 @@ public class EmergencyStateTracker { return; } - mWasEmergencyModeSetOnModem = false; - phone.exitEmergencyMode(m); + synchronized (mLock) { + mWasEmergencyModeSetOnModem = false; + if (waitForPdnDisconnect) { + registerForDataConnectionStateChanges(phone); + mPhoneToExit = phone; + if (mPdnDisconnectionTimeoutMs > 0) { + // To avoid waiting for the disconnection indefinitely. + mHandler.sendEmptyMessageDelayed(MSG_EXIT_EMERGENCY_MODE, + mPdnDisconnectionTimeoutMs); + } + return; + } else { + unregisterForDataConnectionStateChanges(); + mPhoneToExit = null; + } + phone.exitEmergencyMode(m); + } } /** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */ @@ -737,16 +868,76 @@ public class EmergencyStateTracker { public void onEmergencyCallStateChanged(Call.State state, String callId) { if (state == Call.State.ACTIVE) { mActiveEmergencyCalls.add(callId); + if (Objects.equals(mOngoingCallId, callId)) { + Rlog.i(TAG, "call connected " + callId); + if (mPhone != null + && isVoWiFi(mOngoingCallProperties) + && mEmergencyMode == EmergencyConstants.MODE_EMERGENCY_WLAN) { + // Recover normal service in cellular when VoWiFi is connected + mPhone.cancelEmergencyNetworkScan(true, null); + } + } } } /** + * Handles the change of emergency call properties. + * + * @param properties the new call properties. + * @param callId the callId whose state has changed. + */ + public void onEmergencyCallPropertiesChanged(int properties, String callId) { + if (Objects.equals(mOngoingCallId, callId)) { + mOngoingCallProperties = properties; + } + } + + /** + * Handles the radio power off request. + */ + public void onCellularRadioPowerOffRequested() { + synchronized (mLock) { + if (isInEcm()) { + exitEmergencyCallbackMode(null); + } + exitEmergencyModeIfDelayed(); + } + } + + private static boolean isVoWiFi(int properties) { + return (properties & android.telecom.Connection.PROPERTY_WIFI) > 0 + || (properties & android.telecom.Connection.PROPERTY_CROSS_SIM) > 0; + } + + /** * Returns {@code true} if device and carrier support emergency callback mode. */ - private boolean isEmergencyCallbackModeSupported() { - return getConfig(mPhone.getSubId(), - CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, - DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED); + @VisibleForTesting + public boolean isEmergencyCallbackModeSupported() { + int subId = mPhone.getSubId(); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + // If there is no SIM, refer to the saved last carrier configuration with valid + // subscription. + int phoneId = mPhone.getPhoneId(); + Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(phoneId)); + if (savedConfig == null) { + // Exceptional case such as with poor boot performance. + // Usually, the first carrier config change will update the cache. + // But with poor boot performance, the carrier config change + // can be delayed for a long time. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); + savedConfig = Boolean.valueOf( + sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + phoneId, false)); + Rlog.i(TAG, "ECBM value not cached, load from preference"); + mNoSimEcbmSupported.put(Integer.valueOf(phoneId), savedConfig); + } + Rlog.i(TAG, "isEmergencyCallbackModeSupported savedConfig=" + savedConfig); + return savedConfig; + } else { + return getConfig(subId, + CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, + DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED); + } } /** @@ -815,7 +1006,9 @@ public class EmergencyStateTracker { gsmCdmaPhone.notifyEmergencyCallRegistrants(false); // Exit emergency mode on modem. - exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL); + // b/299866883: Wait for the disconnection of ePDN before calling exitEmergencyMode. + exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL, + mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_PS); } mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN; @@ -938,9 +1131,10 @@ public class EmergencyStateTracker { * This should be called once an emergency SMS is sent. * * @param smsId the SMS id on which to end the emergency SMS. - * @param emergencyNumber the emergency number which was used for the emergency SMS. + * @param success the flag specifying whether an emergency SMS is successfully sent or not. + * {@code true} if SMS is successfully sent, {@code false} otherwise. */ - public void endSms(@NonNull String smsId, EmergencyNumber emergencyNumber) { + public void endSms(@NonNull String smsId, boolean success) { mOngoingEmergencySmsIds.remove(smsId); // If the outgoing emergency SMSs are empty, we can try to exit the emergency mode. @@ -953,7 +1147,7 @@ public class EmergencyStateTracker { MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); } } else { - exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS); + exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, false); } clearEmergencySmsInfo(); @@ -1005,8 +1199,10 @@ public class EmergencyStateTracker { boolean isTestEmergencyNumber) { final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; + final SatelliteController satelliteController = SatelliteController.getInstance(); + boolean needToTurnOffSatellite = satelliteController.isSatelliteEnabled(); - if (needToTurnOnRadio) { + if (needToTurnOnRadio || needToTurnOffSatellite) { Rlog.i(TAG, "turnOnRadioAndSwitchDds: phoneId=" + phone.getPhoneId() + " for " + emergencyTypeToString(emergencyType)); if (mRadioOnHelper == null) { @@ -1017,9 +1213,15 @@ public class EmergencyStateTracker { @Override public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { if (!isRadioReady) { - // Could not turn radio on - Rlog.e(TAG, "Failed to turn on radio."); - completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF); + if (satelliteController.isSatelliteEnabled()) { + // Could not turn satellite off + Rlog.e(TAG, "Failed to turn off satellite modem."); + completeEmergencyMode(emergencyType, DisconnectCause.SATELLITE_ENABLED); + } else { + // Could not turn radio on + Rlog.e(TAG, "Failed to turn on radio."); + completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF); + } } else { switchDdsAndSetEmergencyMode(phone, emergencyType); } @@ -1031,7 +1233,8 @@ public class EmergencyStateTracker { // should be able to make emergency calls at any time after the radio has been // powered on and isn't in the UNAVAILABLE state, even if it is reporting the // OUT_OF_SERVICE state. - return phone.getServiceStateTracker().isRadioOn(); + return phone.getServiceStateTracker().isRadioOn() + && !satelliteController.isSatelliteEnabled(); } @Override @@ -1205,4 +1408,105 @@ public class EmergencyStateTracker { default: return "UNKNOWN"; } } + + private void onCarrierConfigurationChanged(int slotIndex, int subId) { + Rlog.i(TAG, "onCarrierConfigChanged slotIndex=" + slotIndex + ", subId=" + subId); + + if (slotIndex < 0) { + return; + } + + updateNoSimEcbmSupported(slotIndex, subId); + } + + private void updateNoSimEcbmSupported(int slotIndex, int subId) { + SharedPreferences sp = null; + Boolean savedConfig = mNoSimEcbmSupported.get(Integer.valueOf(slotIndex)); + if (savedConfig == null) { + sp = PreferenceManager.getDefaultSharedPreferences(mContext); + savedConfig = Boolean.valueOf( + sp.getBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, false)); + mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), savedConfig); + Rlog.i(TAG, "updateNoSimEcbmSupported load from preference slotIndex=" + slotIndex + + ", supported=" + savedConfig); + } + + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + // invalid subId + return; + } + + PersistableBundle b = getConfigBundle(subId, KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); + if (b.isEmpty()) { + Rlog.e(TAG, "updateNoSimEcbmSupported empty result"); + return; + } + + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) { + Rlog.i(TAG, "updateNoSimEcbmSupported not carrier specific configuration"); + return; + } + + boolean carrierConfig = b.getBoolean(KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); + if (carrierConfig == savedConfig) { + return; + } + + mNoSimEcbmSupported.put(Integer.valueOf(slotIndex), Boolean.valueOf(carrierConfig)); + + if (sp == null) { + sp = PreferenceManager.getDefaultSharedPreferences(mContext); + } + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(KEY_NO_SIM_ECBM_SUPPORT + slotIndex, carrierConfig); + editor.apply(); + + Rlog.i(TAG, "updateNoSimEcbmSupported preference updated slotIndex=" + slotIndex + + ", supported=" + carrierConfig); + } + + /** For test purpose only */ + @VisibleForTesting + public void setPdnDisconnectionTimeoutMs(int timeout) { + mPdnDisconnectionTimeoutMs = timeout; + } + + private void exitEmergencyModeIfDelayed() { + synchronized (mLock) { + if (mPhoneToExit != null) { + unregisterForDataConnectionStateChanges(); + mPhoneToExit.exitEmergencyMode( + mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE, + Integer.valueOf(EMERGENCY_TYPE_CALL))); + mPhoneToExit = null; + } + } + } + + /** + * Registers for changes to data connection state. + */ + private void registerForDataConnectionStateChanges(Phone phone) { + if ((mDataConnectionStateListener != null) || (phone == null)) { + return; + } + Rlog.i(TAG, "registerForDataConnectionStateChanges"); + + mDataConnectionStateListener = new PreciseDataConnectionStateListener(); + mTelephonyManagerProxy.registerTelephonyCallback(phone.getSubId(), + mHandler::post, mDataConnectionStateListener); + } + + /** + * Unregisters for changes to data connection state. + */ + private void unregisterForDataConnectionStateChanges() { + if (mDataConnectionStateListener == null) { + return; + } + Rlog.i(TAG, "unregisterForDataConnectionStateChanges"); + + mTelephonyManagerProxy.unregisterTelephonyCallback(mDataConnectionStateListener); + mDataConnectionStateListener = null; + } } diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 5b1f36d961..dae808adb5 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -171,6 +171,7 @@ public final class GsmSMSDispatcher extends SMSDispatcher { if(mPhone.getServiceState().getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_NR) { tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE); + notifySmsSentFailedToEmergencyStateTracker(tracker); return; } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 3ab9fd7872..b21d45da25 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -23,6 +23,8 @@ import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_REGIS import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_RAT_BLOCK; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; @@ -47,6 +49,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.app.Activity; import android.app.Notification; @@ -120,6 +123,8 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.metrics.ImsStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -454,14 +459,15 @@ public class ImsPhone extends ImsPhoneBase { } // Constructors - public ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone) { - this(context, notifier, defaultPhone, ImsManager::getInstance, false); + public ImsPhone(Context context, PhoneNotifier notifier, + Phone defaultPhone, FeatureFlags featureFlags) { + this(context, notifier, defaultPhone, ImsManager::getInstance, false, featureFlags); } @VisibleForTesting public ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone, - ImsManagerFactory imsManagerFactory, boolean unitTestMode) { - super("ImsPhone", context, notifier, unitTestMode); + ImsManagerFactory imsManagerFactory, boolean unitTestMode, FeatureFlags featureFlags) { + super("ImsPhone", context, notifier, unitTestMode, featureFlags); mDefaultPhone = defaultPhone; mImsManagerFactory = imsManagerFactory; @@ -480,7 +486,7 @@ public class ImsPhone extends ImsPhoneBase { .inject(ImsNrSaModeHandler.class.getName()) .makeImsNrSaModeHandler(this); mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName()) - .makeImsPhoneCallTracker(this); + .makeImsPhoneCallTracker(this, featureFlags); mCT.registerPhoneStateListener(mExternalCallTracker); mExternalCallTracker.setCallPuller(mCT); @@ -2477,7 +2483,7 @@ public class ImsPhone extends ImsPhoneBase { setServiceState(ServiceState.STATE_IN_SERVICE); getDefaultPhone().setImsRegistrationState(true); mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); - mImsStats.onImsRegistered(imsRadioTech); + mImsStats.onImsRegistered(attributes); mImsNrSaModeHandler.onImsRegistered( attributes.getRegistrationTechnology(), attributes.getFeatureTags()); updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, @@ -2523,10 +2529,21 @@ public class ImsPhone extends ImsPhoneBase { if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK) || (suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT)) { suggestedModemAction = suggestedAction; + } else if (mFeatureFlags.addRatRelatedSuggestedActionToImsRegistration()) { + if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK) + || (suggestedAction == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK)) { + suggestedModemAction = suggestedAction; + } } } updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, imsRadioTech, suggestedModemAction); + + if (mFeatureFlags.clearCachedImsPhoneNumberWhenDeviceLostImsRegistration()) { + // Clear the phone number from P-Associated-Uri + setCurrentSubscriberUris(null); + clearPhoneNumberForSourceIms(); + } } @Override @@ -2537,6 +2554,19 @@ public class ImsPhone extends ImsPhoneBase { } }; + /** Clear the IMS phone number from IMS associated Uris when IMS registration is lost. */ + @VisibleForTesting + @FlaggedApi(Flags.FLAG_CLEAR_CACHED_IMS_PHONE_NUMBER_WHEN_DEVICE_LOST_IMS_REGISTRATION) + public void clearPhoneNumberForSourceIms() { + int subId = getSubId(); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return; + } + + if (DBG) logd("clearPhoneNumberForSourceIms"); + mSubscriptionManagerService.setNumberFromIms(subId, new String("")); + } + /** Sets the IMS phone number from IMS associated URIs, if any found. */ @VisibleForTesting public void setPhoneNumberForSourceIms(Uri[] uris) { @@ -2706,9 +2736,13 @@ public class ImsPhone extends ImsPhoneBase { @RegistrationManager.SuggestedAction int suggestedAction) { if (regState == mImsRegistrationState) { + // In NOT_REGISTERED state, the current PLMN can be blocked with a suggested action. + // But in this case, the same behavior is able to occur in different PLMNs with + // same radio tech and suggested action. if ((regState == REGISTRATION_STATE_REGISTERED && imsRadioTech == mImsRegistrationTech) || (regState == REGISTRATION_STATE_NOT_REGISTERED - && suggestedAction == mImsRegistrationSuggestedAction + && suggestedAction == SUGGESTED_ACTION_NONE + && mImsRegistrationSuggestedAction == SUGGESTED_ACTION_NONE && imsRadioTech == mImsDeregistrationTech)) { // Filter duplicate notification. return; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 8a1041dec3..c5a7ecffe3 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -43,6 +43,7 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.telephony.Rlog; @@ -58,8 +59,9 @@ abstract class ImsPhoneBase extends Phone { private PhoneConstants.State mState = PhoneConstants.State.IDLE; public ImsPhoneBase(String name, Context context, PhoneNotifier notifier, - boolean unitTestMode) { - super(name, notifier, context, new ImsPhoneCommandInterface(context), unitTestMode); + boolean unitTestMode, FeatureFlags featureFlags) { + super(name, notifier, context, new ImsPhoneCommandInterface(context), unitTestMode, + featureFlags); } @Override diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index c3ee0f6060..e95433c2ee 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -148,6 +148,7 @@ import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; import com.android.internal.telephony.metrics.CallQualityMetrics; @@ -310,8 +311,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // activeCall could be null if the foreground call is in a disconnected // state. If either of the calls is null there is no need to check if // one will be disconnected on answer. + // Use VideoProfile.STATE_BIDIRECTIONAL to not affect existing + // implementation. Video state of user response is handled in acceptCall(). boolean answeringWillDisconnect = - shouldDisconnectActiveCallOnAnswer(activeCall, imsCall); + shouldDisconnectActiveCallOnAnswer(activeCall, imsCall, + VideoProfile.STATE_BIDIRECTIONAL); conn.setActiveCallDisconnectedOnAnswer(answeringWillDisconnect); } } @@ -664,6 +668,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private static final int EVENT_START_IMS_TRAFFIC_DONE = 33; private static final int EVENT_CONNECTION_SETUP_FAILURE = 34; private static final int EVENT_NEW_ACTIVE_CALL_STARTED = 35; + private static final int EVENT_PROVISIONING_CHANGED = 36; private static final int TIMEOUT_HANGUP_PENDINGMO = 500; @@ -673,6 +678,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private static final int TIMEOUT_PARTICIPANT_CONNECT_TIME_CACHE_MS = 60000; //ms + private static final int DELAY_STACKING_PROVISIONING_CHANGES_MILLIS = 50; //ms + // Following values are for mHoldSwitchingState private enum HoldSwapState { // Not in the middle of a hold/swap operation @@ -1235,17 +1242,39 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } + private final ConcurrentLinkedQueue<ProvisioningItem> mProvisioningItemQueue = + new ConcurrentLinkedQueue<>(); + + private static class ProvisioningItem { + final int mItem; + final Object mValue; + ProvisioningItem(int item, int value) { + this.mItem = item; + this.mValue = Integer.valueOf(value); + } + + ProvisioningItem(int item, String value) { + this.mItem = item; + this.mValue = value; + } + } + + private @NonNull final FeatureFlags mFeatureFlags; + //***** Events //***** Constructors - public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory) { - this(phone, factory, phone.getContext().getMainExecutor()); + public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory, + FeatureFlags featureFlags) { + this(phone, factory, phone.getContext().getMainExecutor(), featureFlags); } @VisibleForTesting - public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory, Executor executor) { + public ImsPhoneCallTracker(ImsPhone phone, ConnectorFactory factory, Executor executor, + FeatureFlags featureFlags) { this.mPhone = phone; + mFeatureFlags = featureFlags; mConnectorFactory = factory; if (executor != null) { mExecutor = executor; @@ -2189,7 +2218,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { ImsCall ringingCall = mRingingCall.getImsCall(); if (mForegroundCall.hasConnections() && mRingingCall.hasConnections()) { answeringWillDisconnect = - shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall); + shouldDisconnectActiveCallOnAnswer(activeCall, ringingCall, videoState); } // Cache video state for pending MT call. @@ -4590,37 +4619,67 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private final ProvisioningManager.Callback mConfigCallback = new ProvisioningManager.Callback() { - @Override - public void onProvisioningIntChanged(int item, int value) { - sendConfigChangedIntent(item, Integer.toString(value)); - if ((mImsManager != null) - && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED - || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED - || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) { - // Update Ims Service state to make sure updated provisioning values take effect - // immediately. - updateImsServiceConfig(); - } - } + @Override + public void onProvisioningIntChanged(int item, int value) { + // if updateImsServiceByGatheringProvisioningChanges feature is enabled, + // Provisioning items are processed all at once by queuing and sending message. + if (mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) { + queueAndSendProvisioningChanged(new ProvisioningItem(item, value)); + return; + } + // run belows when updateImsServiceByGatheringProvisioningChanges feature is + // disabled only + + sendConfigChangedIntent(item, Integer.toString(value)); + if ((mImsManager != null) + && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) { + // Update Ims Service state to make sure updated provisioning values take + // effect immediately. + updateImsServiceConfig(); + } + } - @Override - public void onProvisioningStringChanged(int item, String value) { - sendConfigChangedIntent(item, value); - } + @Override + public void onProvisioningStringChanged(int item, String value) { + if (mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) { + queueAndSendProvisioningChanged(new ProvisioningItem(item, value)); + return; + } + // run belows when updateImsServiceByGatheringProvisioningChanges feature is + // disabled only - // send IMS_CONFIG_CHANGED intent for older services that do not implement the new callback - // interface. - private void sendConfigChangedIntent(int item, String value) { - log("sendConfigChangedIntent - [" + item + ", " + value + "]"); - Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED); - configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item); - configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value); - if (mPhone != null && mPhone.getContext() != null) { - mPhone.getContext().sendBroadcast( - configChangedIntent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - } - } - }; + sendConfigChangedIntent(item, value); + } + + // send IMS_CONFIG_CHANGED intent for older services that do not implement the new + // callback interface. + private void sendConfigChangedIntent(int item, String value) { + log("sendConfigChangedIntent - [" + item + ", " + value + "]"); + Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED); + configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item); + configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value); + if (mPhone != null && mPhone.getContext() != null) { + mPhone.getContext().sendBroadcast(configChangedIntent, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + } + } + + private void queueAndSendProvisioningChanged(ProvisioningItem provisioningItem) { + if (!mFeatureFlags.updateImsServiceByGatheringProvisioningChanges()) { + return; + } + + boolean bQueueOffer = mProvisioningItemQueue.offer(provisioningItem); + // Checks the Handler Message Queue and schedules a new message with small delay + // to avoid stacking multiple redundant event only if it doesn't exist. + if (bQueueOffer && !hasMessages(EVENT_PROVISIONING_CHANGED)) { + sendMessageDelayed(obtainMessage(EVENT_PROVISIONING_CHANGED), + DELAY_STACKING_PROVISIONING_CHANGES_MILLIS); + } + } + }; public void sendCallStartFailedDisconnect(ImsCall imsCall, ImsReasonInfo reasonInfo) { mPendingMO = null; @@ -5011,6 +5070,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } break; } + + case EVENT_PROVISIONING_CHANGED: { + handleProvisioningChanged(); + break; + } } } @@ -5438,11 +5502,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { * * @param activeCall The active call. * @param incomingCall The incoming call. + * @param incomingCallVideoState The media type of incoming call acceptance. + * {@link VideoProfile.VideoState} * @return {@code true} if answering the incoming call will cause the active call to be * disconnected, {@code false} otherwise. */ private boolean shouldDisconnectActiveCallOnAnswer(ImsCall activeCall, - ImsCall incomingCall) { + ImsCall incomingCall, int incomingCallVideoState) { if (activeCall == null || incomingCall == null) { return false; @@ -5457,7 +5523,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { boolean isActiveCallOnWifi = activeCall.isWifiCall(); boolean isVoWifiEnabled = mImsManager.isWfcEnabledByPlatform() && mImsManager.isWfcEnabledByUser(); - boolean isIncomingCallAudio = !incomingCall.isVideoCall(); + boolean isIncomingCallAudio = true; + if (!mFeatureFlags.terminateActiveVideoCallWhenAcceptingSecondVideoCallAsAudioOnly()) { + isIncomingCallAudio = !incomingCall.isVideoCall(); + } else { + isIncomingCallAudio = !incomingCall.isVideoCall() + || incomingCallVideoState == VideoProfile.STATE_AUDIO_ONLY; + } + log("shouldDisconnectActiveCallOnAnswer : isActiveCallVideo=" + isActiveCallVideo + " isActiveCallOnWifi=" + isActiveCallOnWifi + " isIncomingCallAudio=" + isIncomingCallAudio + " isVowifiEnabled=" + isVoWifiEnabled); @@ -6210,4 +6283,47 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mImsTrafficSessions.forEachKey(1, token -> mPhone.stopImsTraffic(token, null)); mImsTrafficSessions.clear(); } + + /** + * Process provisioning changes all at once. + */ + private void handleProvisioningChanged() { + boolean bNeedUpdateImsServiceConfig = false; + ProvisioningItem provisioningItem; + while ((provisioningItem = mProvisioningItemQueue.poll()) != null) { + int item = provisioningItem.mItem; + if (provisioningItem.mValue instanceof Integer) { + sendConfigChangedIntent(item, provisioningItem.mValue.toString()); + if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED) { + bNeedUpdateImsServiceConfig = true; + } + } else if (provisioningItem.mValue instanceof String) { + sendConfigChangedIntent(item, provisioningItem.mValue.toString()); + } + } + if (bNeedUpdateImsServiceConfig) { + // Update Ims Service state to make sure updated provisioning values take effect. + updateImsServiceConfig(); + } + } + + /** + * send IMS_CONFIG_CHANGED intent for older services that do not implement the new callback + * interface + * + * @param item provisioning item + * @param value provisioning value + */ + private void sendConfigChangedIntent(int item, String value) { + log("sendConfigChangedIntent - [" + item + ", " + value + "]"); + Intent configChangedIntent = new Intent(ImsConfig.ACTION_IMS_CONFIG_CHANGED); + configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item); + configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value); + if (mPhone != null && mPhone.getContext() != null) { + mPhone.getContext().sendBroadcast( + configChangedIntent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + } + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java index 71257636ef..a7a9129196 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java @@ -57,14 +57,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void getIccSlotsStatus(Message result) { - } - - @Override - public void setLogicalToPhysicalSlotMapping(int[] physicalSlots, Message result) { - } - - @Override public void supplyIccPin(String pin, Message result) { } @@ -107,10 +99,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - @Deprecated public void getPDPContextList(Message result) { - } - - @Override public void getDataCallList(Message result) { } @@ -134,14 +122,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void getIMEI(Message result) { - } - - @Override - public void getIMEISV(Message result) { - } - - @Override public void hangupConnection (int gsmIndex, Message result) { } @@ -189,15 +169,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface public void getLastCallFailCause (Message result) { } - @Deprecated - @Override - public void getLastPdpFailCause (Message result) { - } - - @Override - public void getLastDataCallFailCause (Message result) { - } - @Override public void setMute (boolean enableMute, Message response) { } @@ -286,10 +257,9 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message result) { + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean allowRoaming, + int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, Message result) { } @Override @@ -416,18 +386,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void resetRadio(Message result) { - } - - @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - } - - @Override - public void invokeOemRilRequestStrings(String[] strings, Message response) { - } - - @Override public void setBandMode (int bandMode, Message response) { } @@ -596,11 +554,11 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) { + public void setInitialAttachApn(DataProfile dataProfile, Message result) { } @Override - public void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result) { + public void setDataProfile(DataProfile[] dps, Message result) { } @Override @@ -640,18 +598,6 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface } @Override - public void startLceService(int reportIntervalMs, boolean pullMode, Message result) { - } - - @Override - public void stopLceService(Message result) { - } - - @Override - public void pullLceData(Message result) { - } - - @Override public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo, Message result) { } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java index 8f82328aba..0ae149c23b 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneFactory.java @@ -20,6 +20,7 @@ import android.content.Context; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.telephony.Rlog; /** @@ -35,10 +36,10 @@ public class ImsPhoneFactory { * @return the {@code ImsPhone} object */ public static ImsPhone makePhone(Context context, - PhoneNotifier phoneNotifier, Phone defaultPhone) { + PhoneNotifier phoneNotifier, Phone defaultPhone, FeatureFlags featureFlags) { try { - return new ImsPhone(context, phoneNotifier, defaultPhone); + return new ImsPhone(context, phoneNotifier, defaultPhone, featureFlags); } catch (Exception e) { Rlog.e("VoltePhoneFactory", "makePhone", e); return null; diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 0fd97ba25e..387495e109 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -42,7 +42,7 @@ import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; -import java.util.List; +import java.util.Set; /** * Generates metrics related to data stall recovery events per phone ID for the pushed atom. @@ -103,8 +103,9 @@ public class DataStallRecoveryStats { dataNetworkController.registerDataNetworkControllerCallback( new DataNetworkControllerCallback(mHandler::post) { @Override - public void onInternetDataNetworkConnected( - @NonNull List<DataNetwork> internetNetworks) { + public void onConnectedInternetDataNetworksChanged( + @NonNull Set<DataNetwork> internetNetworks) { + mIfaceName = null; for (DataNetwork dataNetwork : internetNetworks) { mIfaceName = dataNetwork.getLinkProperties().getInterfaceName(); break; @@ -112,11 +113,6 @@ public class DataStallRecoveryStats { } @Override - public void onInternetDataNetworkDisconnected() { - mIfaceName = null; - } - - @Override public void onPhysicalLinkStatusChanged(@LinkStatus int status) { mInternetLinkStatus = status; } diff --git a/src/java/com/android/internal/telephony/metrics/ImsStats.java b/src/java/com/android/internal/telephony/metrics/ImsStats.java index 427595ff8c..04c9677453 100644 --- a/src/java/com/android/internal/telephony/metrics/ImsStats.java +++ b/src/java/com/android/internal/telephony/metrics/ImsStats.java @@ -23,6 +23,7 @@ import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPAB import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT; import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO; import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; @@ -39,6 +40,7 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RegistrationManager.ImsRegistrationState; import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; @@ -197,7 +199,7 @@ public class ImsStats { @ImsRegistrationState private int mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; private long mLastTimestamp; - @Nullable private ImsRegistrationStats mLastRegistrationStats; + private ImsRegistrationStats mLastRegistrationStats; @TransportType int mLastTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; // Available features are those reported by ImsService to be available for use. private MmTelCapabilities mLastAvailableFeatures = new MmTelCapabilities(); @@ -210,6 +212,10 @@ public class ImsStats { public ImsStats(ImsPhone phone) { mPhone = phone; mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); + + mLastRegistrationStats = getDefaultImsRegistrationStats(); + updateImsRegistrationStats(); + mLastTimestamp = getTimeMillis(); } /** @@ -221,40 +227,52 @@ public class ImsStats { public synchronized void conclude() { long now = getTimeMillis(); - // Currently not tracking time spent on registering. - if (mLastRegistrationState == REGISTRATION_STATE_REGISTERED) { - ImsRegistrationStats stats = copyOf(mLastRegistrationStats); - long duration = now - mLastTimestamp; + long duration = now - mLastTimestamp; + if (duration < MIN_REGISTRATION_DURATION_MILLIS) { + logw("conclude: discarding transient stats, duration=%d", duration); + } else { + ImsRegistrationStats stats = copyOfDimensionsOnly(mLastRegistrationStats); - if (duration < MIN_REGISTRATION_DURATION_MILLIS) { - logw("conclude: discarding transient stats, duration=%d", duration); - } else { - stats.registeredMillis = duration; - - stats.voiceAvailableMillis = - mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; - stats.videoAvailableMillis = - mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; - stats.utAvailableMillis = - mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; - stats.smsAvailableMillis = - mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; - - MmTelCapabilities lastCapableFeatures = - stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN - ? mLastWlanCapableFeatures - : mLastWwanCapableFeatures; - stats.voiceCapableMillis = - lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; - stats.videoCapableMillis = - lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; - stats.utCapableMillis = - lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; - stats.smsCapableMillis = - lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; - - mStorage.addImsRegistrationStats(stats); + if (stats.rat == TelephonyManager.NETWORK_TYPE_UNKNOWN) { + logw("conclude: discarding UNKNOWN RAT, duration=%d", duration); + mLastTimestamp = now; + return; } + + switch (mLastRegistrationState) { + case REGISTRATION_STATE_REGISTERED: + stats.registeredMillis = duration; + + stats.voiceAvailableMillis = + mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; + stats.videoAvailableMillis = + mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; + stats.utAvailableMillis = + mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; + stats.smsAvailableMillis = + mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; + + MmTelCapabilities lastCapableFeatures = + stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN + ? mLastWlanCapableFeatures + : mLastWwanCapableFeatures; + stats.voiceCapableMillis = + lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0; + stats.videoCapableMillis = + lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0; + stats.utCapableMillis = + lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0; + stats.smsCapableMillis = + lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0; + break; + case REGISTRATION_STATE_REGISTERING: + stats.registeringMillis = duration; + break; + case REGISTRATION_STATE_NOT_REGISTERED: + stats.unregisteredMillis = duration; + break; + } + mStorage.addImsRegistrationStats(stats); } mLastTimestamp = now; @@ -271,10 +289,11 @@ public class ImsStats { (newRat == TelephonyManager.NETWORK_TYPE_IWLAN) ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - if (mLastRegistrationStats != null && mLastRegistrationStats.rat != newRat) { + if (mLastRegistrationStats.rat != newRat) { mLastRegistrationStats.rat = newRat; ratChanged = true; } + mLastRegistrationStats.isIwlanCrossSim = radioTech == REGISTRATION_TECH_CROSS_SIM; boolean voiceAvailableNow = capabilities.isCapable(CAPABILITY_TYPE_VOICE); boolean voiceAvailabilityChanged = @@ -308,21 +327,24 @@ public class ImsStats { conclude(); mLastTransportType = imsRadioTech; - mLastRegistrationStats = getDefaultImsRegistrationStats(); + updateImsRegistrationStats(); mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech); mLastRegistrationState = REGISTRATION_STATE_REGISTERING; } /** Updates the stats when IMS registration succeeds. */ - public synchronized void onImsRegistered(@TransportType int imsRadioTech) { + public synchronized void onImsRegistered(ImsRegistrationAttributes attributes) { conclude(); - mLastTransportType = imsRadioTech; - // NOTE: mLastRegistrationStats can be null (no registering phase). - if (mLastRegistrationStats == null) { - mLastRegistrationStats = getDefaultImsRegistrationStats(); + mLastTransportType = attributes.getTransportType(); + // NOTE: status can be unregistered (no registering phase) + if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED) { + updateImsRegistrationStats(); } - mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech); + mLastRegistrationStats.rat = + convertTransportTypeToNetworkType(attributes.getTransportType()); + mLastRegistrationStats.isIwlanCrossSim = attributes.getRegistrationTechnology() + == REGISTRATION_TECH_CROSS_SIM; mLastRegistrationState = REGISTRATION_STATE_REGISTERED; } @@ -331,16 +353,16 @@ public class ImsStats { conclude(); // Generate end reason atom. - // NOTE: mLastRegistrationStats can be null (no registering phase). ImsRegistrationTermination termination = new ImsRegistrationTermination(); - if (mLastRegistrationStats != null) { + if (mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) { termination.carrierId = mLastRegistrationStats.carrierId; termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat); + termination.isIwlanCrossSim = mLastRegistrationStats.isIwlanCrossSim; } else { + // if the registration state is from unregistered to unregistered. termination.carrierId = mPhone.getDefaultPhone().getCarrierId(); - // We cannot tell whether the registration was intended for WWAN or WLAN - termination.ratAtEnd = TelephonyManager.NETWORK_TYPE_UNKNOWN; } + termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat); termination.isMultiSim = SimSlotState.isMultiSim(); termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); termination.reasonCode = reasonInfo.getCode(); @@ -351,16 +373,20 @@ public class ImsStats { // Reset state to unregistered. mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; - mLastRegistrationStats = null; mLastAvailableFeatures = new MmTelCapabilities(); } /** Updates the RAT when service state changes. */ public synchronized void onServiceStateChanged(ServiceState state) { - if (mLastTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - && mLastRegistrationStats != null) { - mLastRegistrationStats.rat = - ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS); + conclude(); + + @NetworkType int newRat = state.getDataNetworkType(); + MmTelCapabilities lastCapableFeatures = getLastCapableFeaturesForNetworkType(newRat); + + if (lastCapableFeatures != null) { + mLastRegistrationStats.rat = newRat; + } else { + mLastRegistrationStats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN; } } @@ -370,7 +396,7 @@ public class ImsStats { */ @NetworkType public synchronized int getImsVoiceRadioTech() { - if (mLastRegistrationStats == null + if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED || !mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE)) { return TelephonyManager.NETWORK_TYPE_UNKNOWN; } @@ -404,17 +430,35 @@ public class ImsStats { private ImsRegistrationStats getDefaultImsRegistrationStats() { Phone phone = mPhone.getDefaultPhone(); ImsRegistrationStats stats = new ImsRegistrationStats(); - stats.carrierId = phone.getCarrierId(); - stats.simSlotIndex = phone.getPhoneId(); + stats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN; return stats; } + private void updateImsRegistrationStats() { + Phone phone = mPhone.getDefaultPhone(); + mLastRegistrationStats.carrierId = phone.getCarrierId(); + mLastRegistrationStats.simSlotIndex = phone.getPhoneId(); + } + @Nullable private MmTelCapabilities getLastCapableFeaturesForTech(@ImsRegistrationTech int radioTech) { switch (radioTech) { case REGISTRATION_TECH_NONE: return null; case REGISTRATION_TECH_IWLAN: + case REGISTRATION_TECH_CROSS_SIM: + return mLastWlanCapableFeatures; + default: + return mLastWwanCapableFeatures; + } + } + + @Nullable + private MmTelCapabilities getLastCapableFeaturesForNetworkType(@NetworkType int netType) { + switch (netType) { + case TelephonyManager.NETWORK_TYPE_UNKNOWN: + return null; + case TelephonyManager.NETWORK_TYPE_IWLAN: return mLastWlanCapableFeatures; default: return mLastWwanCapableFeatures; @@ -429,6 +473,7 @@ public class ImsStats { case REGISTRATION_TECH_LTE: return TelephonyManager.NETWORK_TYPE_LTE; case REGISTRATION_TECH_IWLAN: + case REGISTRATION_TECH_CROSS_SIM: return TelephonyManager.NETWORK_TYPE_IWLAN; case REGISTRATION_TECH_NR: return TelephonyManager.NETWORK_TYPE_NR; @@ -438,21 +483,13 @@ public class ImsStats { } } - private static ImsRegistrationStats copyOf(ImsRegistrationStats source) { + private static ImsRegistrationStats copyOfDimensionsOnly(ImsRegistrationStats source) { ImsRegistrationStats dest = new ImsRegistrationStats(); dest.carrierId = source.carrierId; dest.simSlotIndex = source.simSlotIndex; dest.rat = source.rat; - dest.registeredMillis = source.registeredMillis; - dest.voiceCapableMillis = source.voiceCapableMillis; - dest.voiceAvailableMillis = source.voiceAvailableMillis; - dest.smsCapableMillis = source.smsCapableMillis; - dest.smsAvailableMillis = source.smsAvailableMillis; - dest.videoCapableMillis = source.videoCapableMillis; - dest.videoAvailableMillis = source.videoAvailableMillis; - dest.utCapableMillis = source.utCapableMillis; - dest.utAvailableMillis = source.utAvailableMillis; + dest.isIwlanCrossSim = source.isIwlanCrossSim; return dest; } diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 3e49139cce..8bd25475b0 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -53,7 +53,9 @@ import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_UNKNOWN; +import static com.android.internal.telephony.util.TelephonyUtils.IS_DEBUGGABLE; +import android.annotation.NonNull; import android.app.StatsManager; import android.content.Context; import android.telephony.SubscriptionManager; @@ -65,6 +67,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; @@ -97,6 +100,8 @@ import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportSession import com.android.internal.telephony.nano.PersistAtomsProto.UceEventStats; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession; +import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.util.ConcurrentUtils; import com.android.telephony.Rlog; @@ -134,34 +139,55 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { DBG ? 10L * MILLIS_PER_SECOND : 23L * MILLIS_PER_HOUR; /** + * Sets atom pull cool down to 4 minutes for userdebug build. + * + * <p>Applies to certain atoms: CellularServiceState. + */ + private static final long CELL_SERVICE_MIN_COOLDOWN_MILLIS = + DBG ? 10L * MILLIS_PER_SECOND : + IS_DEBUGGABLE ? 4L * MILLIS_PER_MINUTE : 23L * MILLIS_PER_HOUR; + + /** * Buckets with less than these many calls will be dropped. * * <p>Applies to metrics with duration fields. Currently used by voice call RAT usages. */ private static final long MIN_CALLS_PER_BUCKET = DBG ? 0L : 5L; - /** Bucket size in milliseconds to round call durations into. */ + /** Bucket size in milliseconds to round call durations info. */ private static final long DURATION_BUCKET_MILLIS = DBG ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE; + /** + * Sets smaller bucket size to round call durations for userdebug build. + * + * <p>Applies to certain atoms: CellularServiceState. + */ + private static final long CELL_SERVICE_DURATION_BUCKET_MILLIS = + DBG || IS_DEBUGGABLE ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE; + private final PersistAtomsStorage mStorage; private final DeviceStateHelper mDeviceStateHelper; private final StatsManager mStatsManager; + private final VonrHelper mVonrHelper; private final AirplaneModeStats mAirplaneModeStats; private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet(); private static final Random sRandom = new Random(); - public MetricsCollector(Context context) { - this(context, new PersistAtomsStorage(context), new DeviceStateHelper(context)); + public MetricsCollector(Context context, @NonNull FeatureFlags featureFlags) { + this(context, new PersistAtomsStorage(context), + new DeviceStateHelper(context), new VonrHelper(featureFlags)); } /** Allows dependency injection. Used during unit tests. */ @VisibleForTesting public MetricsCollector( - Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper) { + Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper, + VonrHelper vonrHelper) { mStorage = storage; mDeviceStateHelper = deviceStateHelper; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); + mVonrHelper = vonrHelper; if (mStatsManager != null) { // Most (but not all) of these are subject to cooldown specified by MIN_COOLDOWN_MILLIS. registerAtom(CELLULAR_DATA_SERVICE_SWITCH); @@ -193,13 +219,13 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(GBA_EVENT); registerAtom(PER_SIM_STATUS); registerAtom(OUTGOING_SHORT_CODE_SMS); + registerAtom(EMERGENCY_NUMBERS_INFO); registerAtom(SATELLITE_CONTROLLER); registerAtom(SATELLITE_SESSION); registerAtom(SATELLITE_INCOMING_DATAGRAM); registerAtom(SATELLITE_OUTGOING_DATAGRAM); registerAtom(SATELLITE_PROVISION); registerAtom(SATELLITE_SOS_MESSAGE_RECOMMENDER); - registerAtom(EMERGENCY_NUMBERS_INFO); Rlog.d(TAG, "registered"); } else { Rlog.e(TAG, "could not get StatsManager, atoms not registered"); @@ -276,6 +302,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullPerSimStatus(data); case OUTGOING_SHORT_CODE_SMS: return pullOutgoingShortCodeSms(data); + case EMERGENCY_NUMBERS_INFO: + return pullEmergencyNumbersInfo(data); case SATELLITE_CONTROLLER: return pullSatelliteController(data); case SATELLITE_SESSION: @@ -288,8 +316,6 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullSatelliteProvision(data); case SATELLITE_SOS_MESSAGE_RECOMMENDER: return pullSatelliteSosMessageRecommender(data); - case EMERGENCY_NUMBERS_INFO: - return pullEmergencyNumbersInfo(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; @@ -306,6 +332,11 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return mDeviceStateHelper; } + /** Returns the {@link VonrHelper}. */ + public VonrHelper getVonrHelper() { + return mVonrHelper; + } + /** Updates duration segments and calls {@link PersistAtomsStorage#flushAtoms()}. */ public void flushAtomsStorage() { concludeAll(); @@ -383,7 +414,9 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { SIM_SLOT_STATE, state.numActiveSlots, state.numActiveSims, - state.numActiveEsims)); + state.numActiveEsims, + state.numActiveEsimSlots, + state.numActiveMepSlots)); return StatsManager.PULL_SUCCESS; } @@ -506,7 +539,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { // Include the latest durations concludeServiceStateStats(); CellularServiceState[] persistAtoms = - mStorage.getCellularServiceStates(MIN_COOLDOWN_MILLIS); + mStorage.getCellularServiceStates(CELL_SERVICE_MIN_COOLDOWN_MILLIS); if (persistAtoms != null) { // list is already shuffled when instances were inserted Arrays.stream(persistAtoms) @@ -572,9 +605,14 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { boolean hasDedicatedManagedProfileSub = Arrays.stream(phones) .anyMatch(Phone::isManagedProfile); + UiccSlot[] slots = UiccController.getInstance().getUiccSlots(); + int mepSupportedSlotCount = (int) Arrays.stream(slots) + .filter(UiccSlot::isMultipleEnabledProfileSupported) + .count(); + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true, isAutoDataSwitchOn, mStorage.getAutoDataSwitchToggleCount(), - hasDedicatedManagedProfileSub)); + hasDedicatedManagedProfileSub, mepSupportedSlotCount)); return StatsManager.PULL_SUCCESS; } @@ -777,7 +815,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { perSimStatus.minimumVoltageClass, // simVoltageClass perSimStatus.userModifiedApnTypes, // userModifiedApnTypeBitmask perSimStatus.unmeteredNetworks, // unmeteredNetworks - perSimStatus.vonrEnabled); // vonrEnabled + perSimStatus.vonrEnabled, // vonrEnabled + perSimStatus.crossSimCallingEnabled); // crossSimCallingEnabled data.add(statsEvent); result = StatsManager.PULL_SUCCESS; } @@ -797,6 +836,21 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } + private int pullEmergencyNumbersInfo(List<StatsEvent> data) { + boolean isDataLogged = false; + for (Phone phone : getPhonesIfAny()) { + if (phone != null) { + EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker(); + if (tracker != null) { + EmergencyNumbersInfo[] numList = tracker.getEmergencyNumbersProtoArray(); + Arrays.stream(numList).forEach(number -> data.add(buildStatsEvent(number))); + isDataLogged = true; + } + } + } + return isDataLogged ? StatsManager.PULL_SUCCESS : StatsManager.PULL_SKIP; + } + private int pullSatelliteController(List<StatsEvent> data) { SatelliteController[] controllerAtoms = mStorage.getSatelliteControllerStats(MIN_COOLDOWN_MILLIS); @@ -877,21 +931,6 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } - private int pullEmergencyNumbersInfo(List<StatsEvent> data) { - boolean isDataLogged = false; - for (Phone phone : getPhonesIfAny()) { - if (phone != null) { - EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker(); - if (tracker != null) { - EmergencyNumbersInfo[] numList = tracker.getEmergencyNumbersProtoArray(); - Arrays.stream(numList).forEach(number -> data.add(buildStatsEvent(number))); - isDataLogged = true; - } - } - } - return isDataLogged ? StatsManager.PULL_SUCCESS : StatsManager.PULL_SKIP; - } - /** Registers a pulled atom ID {@code atomId}. */ private void registerAtom(int atomId) { mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null, @@ -920,12 +959,14 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { state.simSlotIndex, state.isMultiSim, state.carrierId, - roundAndConvertMillisToSeconds(state.totalTimeMillis), + roundAndConvertMillisToSeconds(state.totalTimeMillis, + CELL_SERVICE_DURATION_BUCKET_MILLIS), state.isEmergencyOnly, state.isInternetPdnUp, state.foldState, state.overrideVoiceService, - state.isDataEnabled); + state.isDataEnabled, + state.isIwlanCrossSim); } private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) { @@ -979,7 +1020,12 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { session.lastKnownRat, session.foldState, session.ratSwitchCountAfterConnected, - session.handoverInProgress); + session.handoverInProgress, + session.isIwlanCrossSimAtStart, + session.isIwlanCrossSimAtEnd, + session.isIwlanCrossSimAtConnected, + session.vonrEnabled); + } private static StatsEvent buildStatsEvent(IncomingSms sms) { @@ -1051,7 +1097,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { dataCallSession.bandAtEnd, dataCallSession.handoverFailureCauses, dataCallSession.handoverFailureRat, - dataCallSession.isNonDds); + dataCallSession.isNonDds, + dataCallSession.isIwlanCrossSim); } private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) { @@ -1068,7 +1115,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { roundAndConvertMillisToSeconds(stats.videoCapableMillis), roundAndConvertMillisToSeconds(stats.videoAvailableMillis), roundAndConvertMillisToSeconds(stats.utCapableMillis), - roundAndConvertMillisToSeconds(stats.utAvailableMillis)); + roundAndConvertMillisToSeconds(stats.utAvailableMillis), + roundAndConvertMillisToSeconds(stats.registeringMillis), + roundAndConvertMillisToSeconds(stats.unregisteredMillis), + stats.isIwlanCrossSim); } private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) { @@ -1081,7 +1131,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { termination.reasonCode, termination.extraCode, termination.extraMessage, - termination.count); + termination.count, + termination.isIwlanCrossSim); } private static StatsEvent buildStatsEvent(NetworkRequestsV2 networkRequests) { @@ -1247,6 +1298,21 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { shortCodeSms.shortCodeSmsCount); } + private static StatsEvent buildStatsEvent(EmergencyNumbersInfo emergencyNumber) { + return TelephonyStatsLog.buildStatsEvent( + EMERGENCY_NUMBERS_INFO, + emergencyNumber.isDbVersionIgnored, + emergencyNumber.assetVersion, + emergencyNumber.otaVersion, + emergencyNumber.number, + emergencyNumber.countryIso, + emergencyNumber.mnc, + emergencyNumber.route, + emergencyNumber.urns, + emergencyNumber.serviceCategories, + emergencyNumber.sources); + } + private static StatsEvent buildStatsEvent(SatelliteController satelliteController) { return TelephonyStatsLog.buildStatsEvent( SATELLITE_CONTROLLER, @@ -1310,22 +1376,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { stats.countOfTimerStarted, stats.isImsRegistered, stats.cellularServiceState, - stats.count); - } - - private static StatsEvent buildStatsEvent(EmergencyNumbersInfo emergencyNumber) { - return TelephonyStatsLog.buildStatsEvent( - EMERGENCY_NUMBERS_INFO, - emergencyNumber.isDbVersionIgnored, - emergencyNumber.assetVersion, - emergencyNumber.otaVersion, - emergencyNumber.number, - emergencyNumber.countryIso, - emergencyNumber.mnc, - emergencyNumber.route, - emergencyNumber.urns, - emergencyNumber.serviceCategories, - emergencyNumber.sources); + stats.count, + stats.isMultiSim, + stats.recommendingHandoverType, + stats.isSatelliteAllowedInCurrentLocation); } /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ @@ -1342,8 +1396,15 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { * Rounds the duration and converts it from milliseconds to seconds. */ private static int roundAndConvertMillisToSeconds(long valueMillis) { - long roundedValueMillis = Math.round((double) valueMillis / DURATION_BUCKET_MILLIS) - * DURATION_BUCKET_MILLIS; + return roundAndConvertMillisToSeconds(valueMillis, DURATION_BUCKET_MILLIS); + } + + /** + * Rounds the duration and converts it from milliseconds to seconds. + */ + private static int roundAndConvertMillisToSeconds(long valueMillis, long durationBucketSize) { + long roundedValueMillis = Math.round((double) valueMillis / durationBucketSize) + * durationBucketSize; return (int) (roundedValueMillis / MILLIS_PER_SECOND); } diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java index bc1edc3769..70ff4914d7 100644 --- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java +++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java @@ -32,6 +32,7 @@ import android.annotation.Nullable; import android.database.Cursor; import android.net.Uri; import android.provider.Telephony; +import android.telephony.AnomalyReporter; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -46,9 +47,14 @@ import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; +import com.android.telephony.Rlog; + +import java.util.UUID; /** Stores the per SIM status. */ public class PerSimStatus { + private static final String TAG = "PerSimStatus"; + private static final long BITMASK_2G = TelephonyManager.NETWORK_TYPE_BITMASK_GSM | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS @@ -56,6 +62,9 @@ public class PerSimStatus { | TelephonyManager.NETWORK_TYPE_BITMASK_CDMA | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT; + private static final UUID CROSS_SIM_CALLING_STATUS_ANOMALY_UUID = + UUID.fromString("377e1a33-d4ac-4039-9cc0-f0d8396757f3"); + public final int carrierId; public final int phoneNumberSourceUicc; public final int phoneNumberSourceCarrier; @@ -74,6 +83,8 @@ public class PerSimStatus { public final long unmeteredNetworks; public final boolean vonrEnabled; + public final boolean crossSimCallingEnabled; + /** Returns the current sim status of the given {@link Phone}. */ @Nullable public static PerSimStatus getCurrentState(Phone phone) { @@ -105,7 +116,8 @@ public class PerSimStatus { getMinimumVoltageClass(phone), getUserModifiedApnTypes(phone), persistAtomsStorage.getUnmeteredNetworks(phone.getPhoneId(), carrierId), - isVonrEnabled(phone)); + isVonrEnabled(phone), + isCrossSimCallingEnabled(imsMmTelManager)); } private PerSimStatus( @@ -125,7 +137,8 @@ public class PerSimStatus { int minimumVoltageClass, int userModifiedApnTypes, long unmeteredNetworks, - boolean vonrEnabled) { + boolean vonrEnabled, + boolean crossSimCallingEnabled) { this.carrierId = carrierId; this.phoneNumberSourceUicc = phoneNumberSourceUicc; this.phoneNumberSourceCarrier = phoneNumberSourceCarrier; @@ -143,6 +156,18 @@ public class PerSimStatus { this.userModifiedApnTypes = userModifiedApnTypes; this.unmeteredNetworks = unmeteredNetworks; this.vonrEnabled = vonrEnabled; + this.crossSimCallingEnabled = crossSimCallingEnabled; + } + + private static boolean isCrossSimCallingEnabled(ImsMmTelManager imsMmTelManager) { + try { + return imsMmTelManager != null && imsMmTelManager.isCrossSimCallingEnabled(); + } catch (Exception e) { + AnomalyReporter.reportAnomaly(CROSS_SIM_CALLING_STATUS_ANOMALY_UUID, + "Failed to query ImsMmTelManager for cross-SIM calling status!"); + Rlog.e(TAG, e.getMessage()); + } + return false; } @Nullable @@ -278,7 +303,7 @@ public class PerSimStatus { } /** Returns true if VoNR is enabled */ - private static boolean isVonrEnabled(Phone phone) { + static boolean isVonrEnabled(Phone phone) { TelephonyManager telephonyManager = phone.getContext() .getSystemService(TelephonyManager.class); diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index d495ca28c5..101df0de14 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -407,6 +407,8 @@ public class PersistAtomsStorage { existingStats.videoAvailableMillis += stats.videoAvailableMillis; existingStats.utCapableMillis += stats.utCapableMillis; existingStats.utAvailableMillis += stats.utAvailableMillis; + existingStats.registeringMillis += stats.registeringMillis; + existingStats.unregisteredMillis += stats.unregisteredMillis; existingStats.lastUsedMillis = getWallTimeMillis(); } else { stats.lastUsedMillis = getWallTimeMillis(); @@ -1711,7 +1713,8 @@ public class PersistAtomsStorage { && state.isInternetPdnUp == key.isInternetPdnUp && state.foldState == key.foldState && state.overrideVoiceService == key.overrideVoiceService - && state.isDataEnabled == key.isDataEnabled) { + && state.isDataEnabled == key.isDataEnabled + && state.isIwlanCrossSim == key.isIwlanCrossSim) { return state; } } @@ -1759,7 +1762,8 @@ public class PersistAtomsStorage { for (ImsRegistrationStats stats : mAtoms.imsRegistrationStats) { if (stats.carrierId == key.carrierId && stats.simSlotIndex == key.simSlotIndex - && stats.rat == key.rat) { + && stats.rat == key.rat + && stats.isIwlanCrossSim == key.isIwlanCrossSim) { return stats; } } @@ -1775,6 +1779,7 @@ public class PersistAtomsStorage { if (termination.carrierId == key.carrierId && termination.isMultiSim == key.isMultiSim && termination.ratAtEnd == key.ratAtEnd + && termination.isIwlanCrossSim == key.isIwlanCrossSim && termination.setupFailed == key.setupFailed && termination.reasonCode == key.reasonCode && termination.extraCode == key.extraCode @@ -2068,7 +2073,9 @@ public class PersistAtomsStorage { if (stats.isDisplaySosMessageSent == key.isDisplaySosMessageSent && stats.countOfTimerStarted == key.countOfTimerStarted && stats.isImsRegistered == key.isImsRegistered - && stats.cellularServiceState == key.cellularServiceState) { + && stats.cellularServiceState == key.cellularServiceState + && stats.isMultiSim == key.isMultiSim + && stats.recommendingHandoverType == key.recommendingHandoverType) { return stats; } } @@ -2279,6 +2286,10 @@ public class PersistAtomsStorage { normalizeDurationTo24H(stats[i].utCapableMillis, intervalMillis); stats[i].utAvailableMillis = normalizeDurationTo24H(stats[i].utAvailableMillis, intervalMillis); + stats[i].registeringMillis = + normalizeDurationTo24H(stats[i].registeringMillis, intervalMillis); + stats[i].unregisteredMillis = + normalizeDurationTo24H(stats[i].unregisteredMillis, intervalMillis); } return stats; } diff --git a/src/java/com/android/internal/telephony/metrics/RadioPowerStateStats.java b/src/java/com/android/internal/telephony/metrics/RadioPowerStateStats.java new file mode 100644 index 0000000000..f50c2b28d7 --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/RadioPowerStateStats.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.metrics; + +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_RADIO_POWER_STATE_CHANGED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_OFF; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_ON; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_UNAVAILABLE; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_UNKNOWN; + +import android.telephony.Annotation; +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.TelephonyStatsLog; + +/** Logs cellular radio power state changes to statsd */ +public class RadioPowerStateStats { + + /** Logs cellular radio power state changes to statsd */ + public static void onRadioStateChanged(@Annotation.RadioPowerState int state) { + TelephonyStatsLog.write(CELLULAR_RADIO_POWER_STATE_CHANGED, + radioPowerStateToProtoEnum(state)); + } + + private static int radioPowerStateToProtoEnum(@Annotation.RadioPowerState int state) { + switch (state) { + case TelephonyManager.RADIO_POWER_OFF: + return CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_OFF; + case TelephonyManager.RADIO_POWER_ON: + return CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_ON; + case TelephonyManager.RADIO_POWER_UNAVAILABLE: + return CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_UNAVAILABLE; + default: + return CELLULAR_RADIO_POWER_STATE_CHANGED__STATE__RADIO_POWER_STATE_UNKNOWN; + } + } + +} diff --git a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java index 7ff370c252..55eee1a212 100644 --- a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java +++ b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java @@ -732,12 +732,19 @@ public class SatelliteStats { private final int mCountOfTimerStarted; private final boolean mIsImsRegistered; private final int mCellularServiceState; + private final boolean mIsMultiSim; + private final int mRecommendingHandoverType; + private final boolean mIsSatelliteAllowedInCurrentLocation; private SatelliteSosMessageRecommenderParams(Builder builder) { this.mIsDisplaySosMessageSent = builder.mIsDisplaySosMessageSent; this.mCountOfTimerStarted = builder.mCountOfTimerStarted; this.mIsImsRegistered = builder.mIsImsRegistered; this.mCellularServiceState = builder.mCellularServiceState; + this.mIsMultiSim = builder.mIsMultiSim; + this.mRecommendingHandoverType = builder.mRecommendingHandoverType; + this.mIsSatelliteAllowedInCurrentLocation = + builder.mIsSatelliteAllowedInCurrentLocation; } public boolean isDisplaySosMessageSent() { @@ -756,6 +763,18 @@ public class SatelliteStats { return mCellularServiceState; } + public boolean isMultiSim() { + return mIsMultiSim; + } + + public int getRecommendingHandoverType() { + return mRecommendingHandoverType; + } + + public boolean isSatelliteAllowedInCurrentLocation() { + return mIsSatelliteAllowedInCurrentLocation; + } + /** * A builder class to create {@link SatelliteProvisionParams} data structure class */ @@ -764,6 +783,10 @@ public class SatelliteStats { private int mCountOfTimerStarted = -1; private boolean mIsImsRegistered = false; private int mCellularServiceState = -1; + private boolean mIsMultiSim = false; + private int mRecommendingHandoverType = -1; + private boolean mIsSatelliteAllowedInCurrentLocation = false; + /** * Sets resultCode value of {@link SatelliteSosMessageRecommender} atom @@ -803,6 +826,34 @@ public class SatelliteStats { } /** + * Sets isMultiSim value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setIsMultiSim(boolean isMultiSim) { + this.mIsMultiSim = isMultiSim; + return this; + } + + /** + * Sets recommendingHandoverType value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setRecommendingHandoverType(int recommendingHandoverType) { + this.mRecommendingHandoverType = recommendingHandoverType; + return this; + } + + /** + * Sets isSatelliteAllowedInCurrentLocation value of + * {@link SatelliteSosMessageRecommender} atom then returns Builder class. + */ + public Builder setIsSatelliteAllowedInCurrentLocation( + boolean satelliteAllowedInCurrentLocation) { + mIsSatelliteAllowedInCurrentLocation = satelliteAllowedInCurrentLocation; + return this; + } + + /** * Returns SosMessageRecommenderParams, which contains whole component of * {@link SatelliteSosMessageRecommenderParams} atom */ @@ -818,7 +869,11 @@ public class SatelliteStats { + "isDisplaySosMessageSent=" + mIsDisplaySosMessageSent + ", countOfTimerStarted=" + mCountOfTimerStarted + ", isImsRegistered=" + mIsImsRegistered - + ", cellularServiceState=" + mCellularServiceState + ")"; + + ", cellularServiceState=" + mCellularServiceState + + ", isMultiSim=" + mIsMultiSim + + ", recommendingHandoverType=" + mRecommendingHandoverType + + ", isSatelliteAllowedInCurrentLocation=" + + mIsSatelliteAllowedInCurrentLocation + ")"; } } @@ -899,6 +954,9 @@ public class SatelliteStats { proto.countOfTimerStarted = param.getCountOfTimerStarted(); proto.isImsRegistered = param.isImsRegistered(); proto.cellularServiceState = param.getCellularServiceState(); + proto.isMultiSim = param.isMultiSim(); + proto.recommendingHandoverType = param.getRecommendingHandoverType(); + proto.isSatelliteAllowedInCurrentLocation = param.isSatelliteAllowedInCurrentLocation(); proto.count = 1; mAtomsStorage.addSatelliteSosMessageRecommenderStats(proto); } diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index b6563dd4db..d400c2230b 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -32,6 +32,7 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.ServiceState.RoamingType; import android.telephony.TelephonyManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; @@ -45,7 +46,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataService import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; import com.android.telephony.Rlog; -import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -59,6 +60,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { private final Phone mPhone; private final PersistAtomsStorage mStorage; private final DeviceStateHelper mDeviceStateHelper; + private boolean mExistAnyConnectedInternetPdn; public ServiceStateStats(Phone phone) { super(Runnable::run); @@ -88,6 +90,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { CellularServiceState newServiceState = copyOf(state.mServiceState); newServiceState.voiceRat = getVoiceRat(mPhone, getServiceStateForPhone(mPhone)); + newServiceState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone); return new TimestampedServiceState(newServiceState, now); }); addServiceState(lastState, now); @@ -98,14 +101,14 @@ public class ServiceStateStats extends DataNetworkControllerCallback { mPhone.getDataNetworkController().registerDataNetworkControllerCallback(this); } - /** Updates service state when internet pdn gets connected. */ - public void onInternetDataNetworkConnected(@NonNull List<DataNetwork> internetNetworks) { - onInternetDataNetworkChanged(true); - } - - /** Updates service state when internet pdn gets disconnected. */ - public void onInternetDataNetworkDisconnected() { - onInternetDataNetworkChanged(false); + /** Updates service state when internet pdn changed. */ + @Override + public void onConnectedInternetDataNetworksChanged(@NonNull Set<DataNetwork> internetNetworks) { + boolean existAnyConnectedInternetPdn = !internetNetworks.isEmpty(); + if (mExistAnyConnectedInternetPdn != existAnyConnectedInternetPdn) { + mExistAnyConnectedInternetPdn = existAnyConnectedInternetPdn; + onInternetDataNetworkChanged(mExistAnyConnectedInternetPdn); + } } /** Updates the current service state. */ @@ -131,6 +134,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { newState.foldState = mDeviceStateHelper.getFoldState(); newState.overrideVoiceService = mOverrideVoiceService.get(); newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled(); + newState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone); TimestampedServiceState prevState = mLastState.getAndSet(new TimestampedServiceState(newState, now)); addServiceStateAndSwitch( @@ -301,6 +305,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { copy.foldState = state.foldState; copy.overrideVoiceService = state.overrideVoiceService; copy.isDataEnabled = state.isDataEnabled; + copy.isIwlanCrossSim = state.isIwlanCrossSim; return copy; } @@ -359,6 +364,14 @@ public class ServiceStateStats extends DataNetworkControllerCallback { } } + private boolean isCrossSimCallingRegistered(Phone phone) { + if (phone.getImsPhone() != null) { + return phone.getImsPhone().getImsRegistrationTech() + == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; + } + return false; + } + /** Returns RAT used by WWAN if WWAN is in service. */ public static @NetworkType int getRat( ServiceState state, @NetworkRegistrationInfo.Domain int domain) { diff --git a/src/java/com/android/internal/telephony/metrics/SimSlotState.java b/src/java/com/android/internal/telephony/metrics/SimSlotState.java index f840894fe2..59237e16ab 100644 --- a/src/java/com/android/internal/telephony/metrics/SimSlotState.java +++ b/src/java/com/android/internal/telephony/metrics/SimSlotState.java @@ -23,6 +23,9 @@ import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.telephony.Rlog; +import java.util.Arrays; +import java.util.Objects; + /** Snapshots and stores the current SIM state. */ public class SimSlotState { private static final String TAG = SimSlotState.class.getSimpleName(); @@ -30,31 +33,41 @@ public class SimSlotState { public final int numActiveSlots; public final int numActiveSims; public final int numActiveEsims; + public final int numActiveEsimSlots; + public final int numActiveMepSlots; /** Returns the current SIM state. */ public static SimSlotState getCurrentState() { int numActiveSlots = 0; int numActiveSims = 0; int numActiveEsims = 0; + int numActiveEsimSlots = 0; + int numActiveMepSlots = 0; UiccController uiccController = UiccController.getInstance(); // since we cannot hold lock insider UiccController, using getUiccSlots() for length only for (int i = 0; i < uiccController.getUiccSlots().length; i++) { UiccSlot slot = uiccController.getUiccSlot(i); if (slot != null && slot.isActive()) { numActiveSlots++; + if (slot.isEuicc()) { + numActiveEsimSlots++; + } // avoid CardState.isCardPresent() since this should not include restricted cards if (slot.getCardState() == CardState.CARDSTATE_PRESENT) { if (slot.isEuicc()) { // need to check active profiles besides the presence of eSIM cards UiccCard card = slot.getUiccCard(); if (card != null) { - // Check each port on the EuiccCard - UiccPort[] uiccPorts = card.getUiccPortList(); - for (UiccPort port : uiccPorts) { - if (port != null && port.getNumApplications() > 0) { - numActiveSims++; - numActiveEsims++; - } + int numActiveProfiles = (int) Arrays.stream(card.getUiccPortList()) + .filter(Objects::nonNull) + .map(UiccPort::getUiccProfile) + .filter(Objects::nonNull) + .filter(profile -> profile.getNumApplications() > 0) + .count(); + numActiveSims += numActiveProfiles; + numActiveEsims += numActiveProfiles; + if (numActiveProfiles > 1) { + numActiveMepSlots++; } } } else { @@ -64,13 +77,25 @@ public class SimSlotState { } } } - return new SimSlotState(numActiveSlots, numActiveSims, numActiveEsims); + return new SimSlotState( + numActiveSlots, + numActiveSims, + numActiveEsims, + numActiveEsimSlots, + numActiveMepSlots); } - private SimSlotState(int numActiveSlots, int numActiveSims, int numActiveEsims) { + private SimSlotState( + int numActiveSlots, + int numActiveSims, + int numActiveEsims, + int numActiveEsimSlots, + int numActiveMepSlots) { this.numActiveSlots = numActiveSlots; this.numActiveSims = numActiveSims; this.numActiveEsims = numActiveEsims; + this.numActiveEsimSlots = numActiveEsimSlots; + this.numActiveMepSlots = numActiveMepSlots; } /** Returns whether the given phone is using a eSIM. */ diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java index 5d8e027e09..9cf53c90c6 100644 --- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java @@ -36,6 +36,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSIO import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SIGNAL_STRENGTH_AT_END__SIGNAL_STRENGTH_GREAT; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SIGNAL_STRENGTH_AT_END__SIGNAL_STRENGTH_NONE_OR_UNKNOWN; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; @@ -53,6 +54,7 @@ import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -66,6 +68,9 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.analytics.TelephonyAnalytics; +import com.android.internal.telephony.analytics.TelephonyAnalytics.CallAnalytics; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneConnection; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession; @@ -153,6 +158,7 @@ public class VoiceCallSessionStats { */ private final VoiceCallRatTracker mRatUsage = new VoiceCallRatTracker(); + private final @NonNull FeatureFlags mFlags; private final int mPhoneId; private final Phone mPhone; @@ -162,10 +168,13 @@ public class VoiceCallSessionStats { private final DeviceStateHelper mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper(); - public VoiceCallSessionStats(int phoneId, Phone phone) { + private final VonrHelper mVonrHelper = + PhoneFactory.getMetricsCollector().getVonrHelper(); + + public VoiceCallSessionStats(int phoneId, Phone phone, @NonNull FeatureFlags featureFlags) { mPhoneId = phoneId; mPhone = phone; - + mFlags = featureFlags; DataConnectionStateTracker.getInstance(phoneId).start(phone); } @@ -211,6 +220,19 @@ public class VoiceCallSessionStats { proto.disconnectExtraCode = conn.getPreciseDisconnectCause(); proto.disconnectExtraMessage = conn.getVendorDisconnectCause(); proto.callDuration = classifyCallDuration(conn.getDurationMillis()); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + CallAnalytics callAnalytics = telephonyAnalytics.getCallAnalytics(); + if (callAnalytics != null) { + callAnalytics.onCallTerminated(proto.isEmergency, + false /* isOverIms */, + getVoiceRatWithVoNRFix(mPhone, mPhone.getServiceState(), + proto.bearerAtEnd), + proto.simSlotIndex, proto.disconnectReasonCode); + } + } + } finishCall(id); } } @@ -441,6 +463,10 @@ public class VoiceCallSessionStats { @VideoState int videoState = conn.getVideoState(); VoiceCallSession proto = new VoiceCallSession(); + if (mFlags.vonrEnabledMetric()) { + mVonrHelper.updateVonrEnabledState(); + } + proto.bearerAtStart = bearer; proto.bearerAtEnd = bearer; proto.direction = getDirection(conn); @@ -469,6 +495,11 @@ public class VoiceCallSessionStats { proto.videoEnabled = videoState != VideoProfile.STATE_AUDIO_ONLY ? true : false; proto.handoverInProgress = isHandoverInProgress(bearer, proto.isEmergency); + boolean isCrossSimCall = isCrossSimCall(conn); + proto.isIwlanCrossSimAtStart = isCrossSimCall; + proto.isIwlanCrossSimAtEnd = isCrossSimCall; + proto.isIwlanCrossSimAtConnected = isCrossSimCall; + // internal fields for tracking if (getDirection(conn) == VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT) { // MT call setup hasn't begun hence set to 0 @@ -535,6 +566,10 @@ public class VoiceCallSessionStats { // Set device fold state proto.foldState = mDeviceStateHelper.getFoldState(); + if (mFlags.vonrEnabledMetric()) { + proto.vonrEnabled = mVonrHelper.getVonrEnabled(mPhone.getSubId()); + } + mAtomsStorage.addVoiceCallSession(proto); // merge RAT usages to PersistPullers when the call session ends (i.e. no more active calls) @@ -594,7 +629,9 @@ public class VoiceCallSessionStats { proto.setupFailed = false; // Track RAT when voice call is connected. ServiceState serviceState = getServiceState(); - proto.ratAtConnected = getVoiceRatWithVoNRFix(mPhone, serviceState, proto.bearerAtEnd); + @NetworkType int rat = getVoiceRatWithVoNRFix(mPhone, serviceState, proto.bearerAtEnd); + proto.ratAtConnected = rat; + proto.isIwlanCrossSimAtConnected = isCrossSimCall(conn); // Reset list of codecs with the last codec at the present time. In this way, we // track codec quality only after call is connected and not while ringing. resetCodecList(conn); @@ -631,6 +668,7 @@ public class VoiceCallSessionStats { proto.lastKnownRat = rat; } } + proto.isIwlanCrossSimAtEnd = isCrossSimCall(mPhone); } private void finishImsCall(int id, ImsReasonInfo reasonInfo, long durationMillis) { @@ -640,6 +678,18 @@ public class VoiceCallSessionStats { proto.disconnectExtraCode = reasonInfo.mExtraCode; proto.disconnectExtraMessage = ImsStats.filterExtraMessage(reasonInfo.mExtraMessage); proto.callDuration = classifyCallDuration(durationMillis); + if (mPhone != null) { + TelephonyAnalytics telephonyAnalytics = mPhone.getTelephonyAnalytics(); + if (telephonyAnalytics != null) { + CallAnalytics callAnalytics = telephonyAnalytics.getCallAnalytics(); + if (callAnalytics != null) { + callAnalytics.onCallTerminated(proto.isEmergency, true /* isOverIms */ , + getVoiceRatWithVoNRFix( + mPhone, mPhone.getServiceState(), proto.bearerAtEnd), + proto.simSlotIndex, proto.disconnectReasonCode); + } + } + } finishCall(id); } @@ -878,6 +928,21 @@ public class VoiceCallSessionStats { return conn == null ? 0 : (int) conn.getCreateTime(); } + private boolean isCrossSimCall(Connection conn) { + if (conn instanceof ImsPhoneConnection) { + return ((ImsPhoneConnection) conn).isCrossSimCall(); + } + return false; + } + + private boolean isCrossSimCall(Phone phone) { + if (phone.getImsPhone() != null) { + return phone.getImsPhone().getImsRegistrationTech() + == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; + } + return false; + } + @VisibleForTesting protected long getTimeMillis() { return SystemClock.elapsedRealtime(); diff --git a/src/java/com/android/internal/telephony/metrics/VonrHelper.java b/src/java/com/android/internal/telephony/metrics/VonrHelper.java new file mode 100644 index 0000000000..8f14a86fe7 --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/VonrHelper.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.metrics; + +import static com.android.internal.telephony.metrics.MetricsCollector.getPhonesIfAny; +import static com.android.internal.telephony.metrics.PerSimStatus.isVonrEnabled; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.HandlerThread; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.flags.FeatureFlags; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Vonr state handler. + * + * <p>This class is instantiated in {@link MetricsCollector}. +*/ +public class VonrHelper { + private final @NonNull FeatureFlags mFlags; + + private Handler mHandler; + private Map<Integer, Boolean> mPhoneVonrState = new ConcurrentHashMap<>(); + + public VonrHelper(@NonNull FeatureFlags featureFlags) { + this.mFlags = featureFlags; + if (mFlags.vonrEnabledMetric()) { + HandlerThread mHandlerThread = new HandlerThread("VonrHelperThread"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + } + + /** Update vonr_enabled state */ + public void updateVonrEnabledState() { + if (mFlags.vonrEnabledMetric()) { + mHandler.post(mVonrRunnable); + } + } + + @VisibleForTesting + protected Runnable mVonrRunnable = + new Runnable() { + @Override + public void run() { + mPhoneVonrState.clear(); + for (Phone phone : getPhonesIfAny()) { + mPhoneVonrState.put(phone.getSubId(), isVonrEnabled(phone)); + } + } + }; + + /** Get vonr_enabled per subId */ + public boolean getVonrEnabled(int subId) { + if (mFlags.vonrEnabledMetric()) { + return mPhoneVonrState.getOrDefault(subId, false); + } else { + return false; + } + } +} diff --git a/src/java/com/android/internal/telephony/nitz/TEST_MAPPING b/src/java/com/android/internal/telephony/nitz/TEST_MAPPING new file mode 100644 index 0000000000..4063803716 --- /dev/null +++ b/src/java/com/android/internal/telephony/nitz/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksTelephonyTests", + "options": [ + { + "include-filter": "com.android.internal.telephony.nitz." + } + ] + } + ] +} diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index e7f09c23ed..0c68d4b328 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -16,6 +16,9 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; + import android.annotation.NonNull; import android.content.Context; import android.os.Build; @@ -43,9 +46,12 @@ public class DatagramController { @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramDispatcher mDatagramDispatcher; @NonNull private final DatagramReceiver mDatagramReceiver; + public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); public static final int ROUNDING_UNIT = 10; public static final long SATELLITE_ALIGN_TIMEOUT = TimeUnit.SECONDS.toMillis(30); + public static final long DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT = + TimeUnit.SECONDS.toMillis(60); private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; private static final boolean DEBUG = !"user".equals(Build.TYPE); @@ -59,7 +65,7 @@ public class DatagramController { @GuardedBy("mLock") private int mSendPendingCount = 0; @GuardedBy("mLock") - private int mSendErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + private int mSendErrorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; /** Variables used to update onReceiveDatagramStateChanged(). */ @GuardedBy("mLock") private int mReceiveSubId; @@ -69,11 +75,15 @@ public class DatagramController { @GuardedBy("mLock") private int mReceivePendingCount = 0; @GuardedBy("mLock") - private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + private int mReceiveErrorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; private SatelliteDatagram mDemoModeDatagram; private boolean mIsDemoMode = false; private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; + private long mDatagramWaitTimeForConnectedState = DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT; + @GuardedBy("mLock") + @SatelliteManager.SatelliteModemState + private int mSatelltieModemState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; /** * @return The singleton instance of DatagramController. @@ -130,9 +140,9 @@ public class DatagramController { * @param subId The subId of the subscription to register for incoming satellite datagrams. * @param callback The callback to handle incoming datagrams over satellite. * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. */ - @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { return mDatagramReceiver.registerForSatelliteDatagram(subId, callback); } @@ -159,7 +169,7 @@ public class DatagramController { * long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback) { mDatagramReceiver.pollPendingSatelliteDatagrams(subId, callback); @@ -182,7 +192,7 @@ public class DatagramController { * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @@ -267,13 +277,16 @@ public class DatagramController { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { + synchronized (mLock) { + mSatelltieModemState = state; + } mDatagramDispatcher.onSatelliteModemStateChanged(state); mDatagramReceiver.onSatelliteModemStateChanged(state); } - void onDeviceAlignedWithSatellite(boolean isAligned) { - mDatagramDispatcher.onDeviceAlignedWithSatellite(isAligned); - mDatagramReceiver.onDeviceAlignedWithSatellite(isAligned); + void setDeviceAlignedWithSatellite(boolean isAligned) { + mDatagramDispatcher.setDeviceAlignedWithSatellite(isAligned); + mDatagramReceiver.setDeviceAlignedWithSatellite(isAligned); } @VisibleForTesting @@ -284,17 +297,33 @@ public class DatagramController { } } + /** + * Check if Telephony needs to wait for the modem satellite connected to a satellite network + * before transferring datagrams via satellite. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public boolean needsWaitingForSatelliteConnected() { + synchronized (mLock) { + if (SatelliteController.getInstance().isSatelliteAttachRequired() + && mSatelltieModemState != SATELLITE_MODEM_STATE_CONNECTED + && mSatelltieModemState != SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING) { + return true; + } + return false; + } + } + public boolean isSendingInIdleState() { synchronized (mLock) { - return mSendDatagramTransferState == - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + return (mSendDatagramTransferState + == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); } } public boolean isPollingInIdleState() { synchronized (mLock) { - return mReceiveDatagramTransferState == - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + return (mReceiveDatagramTransferState + == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); } } @@ -336,6 +365,11 @@ public class DatagramController { return mAlignTimeoutDuration; } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public long getDatagramWaitTimeForConnectedState() { + return mDatagramWaitTimeForConnectedState; + } + /** * This API can be used by only CTS to update the timeout duration in milliseconds whether * the device is aligned with the satellite for demo mode @@ -351,6 +385,7 @@ public class DatagramController { logd("setSatelliteDeviceAlignedTimeoutDuration: timeoutMillis=" + timeoutMillis); mAlignTimeoutDuration = timeoutMillis; + mDatagramWaitTimeForConnectedState = timeoutMillis; return true; } @@ -369,6 +404,18 @@ public class DatagramController { } } + /** + * This API can be used by only CTS to override the cached value for the device overlay config + * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether + * outgoing satellite datagrams should be sent to modem in demo mode. + * + * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to + * satellite modem or not. + */ + void setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) { + mDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 77b410db3d..e4d16e7a0d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -16,11 +16,15 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; + import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -30,6 +34,7 @@ import android.telephony.SubscriptionManager; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; @@ -39,6 +44,7 @@ import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import java.util.LinkedHashMap; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; @@ -51,6 +57,7 @@ public class DatagramDispatcher extends Handler { private static final int CMD_SEND_SATELLITE_DATAGRAM = 1; private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 2; private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3; + private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; @@ -63,6 +70,8 @@ public class DatagramDispatcher extends Handler { private static AtomicLong mNextDatagramId = new AtomicLong(0); + private AtomicBoolean mShouldSendDatagramToModemInDemoMode = null; + private final Object mLock = new Object(); @GuardedBy("mLock") @@ -187,50 +196,16 @@ public class DatagramDispatcher extends Handler { (SendSatelliteDatagramArgument) request.argument; onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + if (mIsDemoMode && !shouldSendDatagramToModemInDemoMode()) { + AsyncResult.forMessage(onCompleted, SATELLITE_RESULT_SUCCESS, null); + onCompleted.sendToTarget(); + } else { SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram, argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, argument.needFullScreenPointingUI, onCompleted); - break; - } - - Phone phone = request.phone; - if (phone != null) { - phone.sendSatelliteDatagram(onCompleted, argument.datagram, - argument.needFullScreenPointingUI); - } else { - loge("sendSatelliteDatagram: No phone object"); - synchronized (mLock) { - // Remove current datagram from pending map - if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { - mPendingEmergencyDatagramsMap.remove(argument.datagramId); - } else { - mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); - } - - // Update send status - mDatagramController.updateSendStatus(argument.subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, - getPendingDatagramCount(), - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - mDatagramController.updateSendStatus(argument.subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); - - // report phone == null case - reportSendDatagramCompleted(argument, - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - argument.callback.accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - - // Abort sending all the pending datagrams - abortSendingPendingDatagrams(argument.subId, - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } } break; } - case EVENT_SEND_SATELLITE_DATAGRAM_DONE: { ar = (AsyncResult) msg.obj; request = (DatagramDispatcherHandlerRequest) ar.userObj; @@ -239,7 +214,7 @@ public class DatagramDispatcher extends Handler { (SendSatelliteDatagramArgument) request.argument; synchronized (mLock) { - if (mIsDemoMode && (error == SatelliteManager.SATELLITE_ERROR_NONE)) { + if (mIsDemoMode && (error == SatelliteManager.SATELLITE_RESULT_SUCCESS)) { if (argument.skipCheckingSatelliteAligned) { logd("Satellite was already aligned. No need to check alignment again"); } else if (!mIsAligned) { @@ -262,7 +237,7 @@ public class DatagramDispatcher extends Handler { mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); } - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) { // Update send status for current datagram mDatagramController.updateSendStatus(argument.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, @@ -278,7 +253,7 @@ public class DatagramDispatcher extends Handler { } else { mDatagramController.updateSendStatus(argument.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); + 0, SatelliteManager.SATELLITE_RESULT_SUCCESS); // Send response for current datagram argument.callback.accept(error); } @@ -289,7 +264,7 @@ public class DatagramDispatcher extends Handler { getPendingDatagramCount(), error); mDatagramController.updateSendStatus(argument.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); + 0, SatelliteManager.SATELLITE_RESULT_SUCCESS); // Send response for current datagram // after updating datagram transfer state internally. argument.callback.accept(error); @@ -297,7 +272,7 @@ public class DatagramDispatcher extends Handler { mControllerMetricsStats.reportOutgoingDatagramFailCount( argument.datagramType); abortSendingPendingDatagrams(argument.subId, - SatelliteManager.SATELLITE_REQUEST_ABORTED); + SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } } break; @@ -308,6 +283,10 @@ public class DatagramDispatcher extends Handler { break; } + case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: + handleEventDatagramWaitForConnectedStateTimedOut(); + break; + default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; @@ -328,7 +307,7 @@ public class DatagramDispatcher extends Handler { * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @@ -350,14 +329,25 @@ public class DatagramDispatcher extends Handler { mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs); } - // Modem can be busy receiving datagrams, so send datagram only when modem is not busy. - if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { + if (mDatagramController.needsWaitingForSatelliteConnected()) { + logd("sendSatelliteDatagram: wait for satellite connected"); + mDatagramController.updateSendStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, + getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS); + startDatagramWaitForConnectedStateTimer(); + } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { + // Modem can be busy receiving datagrams, so send datagram only when modem is + // not busy. mSendingDatagramInProgress = true; datagramArgs.setDatagramStartTime(); mDatagramController.updateSendStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, - getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS); sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); + } else { + logd("sendSatelliteDatagram: mSendingDatagramInProgress=" + + mSendingDatagramInProgress + ", isPollingInIdleState=" + + mDatagramController.isPollingInIdleState()); } } } @@ -378,7 +368,7 @@ public class DatagramDispatcher extends Handler { } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected void onDeviceAlignedWithSatellite(boolean isAligned) { + protected void setDeviceAlignedWithSatellite(boolean isAligned) { if (mIsDemoMode) { synchronized (mLock) { mIsAligned = isAligned; @@ -426,7 +416,7 @@ public class DatagramDispatcher extends Handler { @NonNull DatagramDispatcherHandlerRequest request) { SatelliteManager.SatelliteException exception = new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_NOT_REACHABLE); + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); AsyncResult.forMessage(message, null, exception); message.sendToTarget(); @@ -474,7 +464,7 @@ public class DatagramDispatcher extends Handler { datagramArg.setDatagramStartTime(); mDatagramController.updateSendStatus(datagramArg.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, - getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS); sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone); } } @@ -488,7 +478,7 @@ public class DatagramDispatcher extends Handler { @GuardedBy("mLock") private void sendErrorCodeAndCleanupPendingDatagrams( LinkedHashMap<Long, SendSatelliteDatagramArgument> pendingDatagramsMap, - @SatelliteManager.SatelliteError int errorCode) { + @SatelliteManager.SatelliteResult int errorCode) { if (pendingDatagramsMap.size() == 0) { return; } @@ -515,7 +505,7 @@ public class DatagramDispatcher extends Handler { */ @GuardedBy("mLock") private void abortSendingPendingDatagrams(int subId, - @SatelliteManager.SatelliteError int errorCode) { + @SatelliteManager.SatelliteResult int errorCode) { logd("abortSendingPendingDatagrams()"); sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, errorCode); sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, errorCode); @@ -525,9 +515,10 @@ public class DatagramDispatcher extends Handler { * Return pending datagram count * @return pending datagram count */ - @GuardedBy("mLock") - private int getPendingDatagramCount() { - return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size(); + public int getPendingDatagramCount() { + synchronized (mLock) { + return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size(); + } } /** @@ -545,7 +536,7 @@ public class DatagramDispatcher extends Handler { } private void reportSendDatagramCompleted(@NonNull SendSatelliteDatagramArgument argument, - @NonNull @SatelliteManager.SatelliteError int resultCode) { + @NonNull @SatelliteManager.SatelliteResult int resultCode) { SatelliteStats.getInstance().onSatelliteOutgoingDatagramMetrics( new SatelliteStats.SatelliteOutgoingDatagramParams.Builder() .setDatagramType(argument.datagramType) @@ -579,6 +570,12 @@ public class DatagramDispatcher extends Handler { } else if (state == SatelliteManager.SATELLITE_MODEM_STATE_IDLE) { sendPendingDatagrams(); } + + if (state == SATELLITE_MODEM_STATE_CONNECTED + && isDatagramWaitForConnectedStateTimerStarted()) { + stopDatagramWaitForConnectedStateTimer(); + sendPendingDatagrams(); + } } } @@ -589,20 +586,100 @@ public class DatagramDispatcher extends Handler { mDatagramController.updateSendStatus( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, - getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED); + getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); + 0, SatelliteManager.SATELLITE_RESULT_SUCCESS); abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_REQUEST_ABORTED); + SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); stopSatelliteAlignedTimer(); + stopDatagramWaitForConnectedStateTimer(); mIsDemoMode = false; mSendSatelliteDatagramRequest = null; mIsAligned = false; } + private void startDatagramWaitForConnectedStateTimer() { + if (isDatagramWaitForConnectedStateTimerStarted()) { + logd("DatagramWaitForConnectedStateTimer is already started"); + return; + } + sendMessageDelayed(obtainMessage( + EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), + mDatagramController.getDatagramWaitTimeForConnectedState()); + } + + private void stopDatagramWaitForConnectedStateTimer() { + removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public boolean isDatagramWaitForConnectedStateTimerStarted() { + return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); + } + + private void handleEventDatagramWaitForConnectedStateTimedOut() { + logw("Timed out to wait for satellite connected before sending datagrams"); + synchronized (mLock) { + // Update send status + mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + 0, SatelliteManager.SATELLITE_RESULT_SUCCESS); + abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + } + } + + private boolean shouldSendDatagramToModemInDemoMode() { + if (mShouldSendDatagramToModemInDemoMode != null) { + return mShouldSendDatagramToModemInDemoMode.get(); + } + + try { + mShouldSendDatagramToModemInDemoMode = new AtomicBoolean( + mContext.getResources().getBoolean( + R.bool.config_send_satellite_datagram_to_modem_in_demo_mode)); + return mShouldSendDatagramToModemInDemoMode.get(); + + } catch (Resources.NotFoundException ex) { + loge("shouldSendDatagramToModemInDemoMode: id= " + + R.bool.config_send_satellite_datagram_to_modem_in_demo_mode + ", ex=" + ex); + return false; + } + } + + /** + * This API can be used by only CTS to override the cached value for the device overlay config + * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether + * outgoing satellite datagrams should be sent to modem in demo mode. + * + * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to + * satellite modem or not. If it is null, the cache will be cleared. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected void setShouldSendDatagramToModemInDemoMode( + @Nullable Boolean shouldSendToModemInDemoMode) { + logd("setShouldSendDatagramToModemInDemoMode(" + (shouldSendToModemInDemoMode == null + ? "null" : shouldSendToModemInDemoMode) + ")"); + + if (shouldSendToModemInDemoMode == null) { + mShouldSendDatagramToModemInDemoMode = null; + } else { + if (mShouldSendDatagramToModemInDemoMode == null) { + mShouldSendDatagramToModemInDemoMode = new AtomicBoolean( + shouldSendToModemInDemoMode); + } else { + mShouldSendDatagramToModemInDemoMode.set(shouldSendToModemInDemoMode); + } + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 06eede122a..3ac1bbd5bd 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; + import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; import android.annotation.NonNull; @@ -65,6 +67,7 @@ public class DatagramReceiver extends Handler { private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 1; private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 2; private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3; + private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; @@ -82,7 +85,10 @@ public class DatagramReceiver extends Handler { private boolean mIsDemoMode = false; @GuardedBy("mLock") private boolean mIsAligned = false; - private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null; + @Nullable + private DatagramReceiverHandlerRequest mDemoPollPendingSatelliteDatagramsRequest = null; + @Nullable + private DatagramReceiverHandlerRequest mPendingPollSatelliteDatagramsRequest = null; private final Object mLock = new Object(); /** @@ -139,12 +145,6 @@ public class DatagramReceiver extends Handler { } catch (Exception e) { loge("Cannot get default shared preferences: " + e); } - - if ((mSharedPreferences != null) && - (!mSharedPreferences.contains(SATELLITE_DATAGRAM_ID_KEY))) { - mSharedPreferences.edit().putLong(SATELLITE_DATAGRAM_ID_KEY, mNextDatagramId.get()) - .commit(); - } } private static final class DatagramReceiverHandlerRequest { @@ -335,11 +335,11 @@ public class DatagramReceiver extends Handler { if (pendingCount <= 0 && satelliteDatagram == null) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE, - pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + pendingCount, SatelliteManager.SATELLITE_RESULT_SUCCESS); } else if (satelliteDatagram != null) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, - pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + pendingCount, SatelliteManager.SATELLITE_RESULT_SUCCESS); long datagramId = getDatagramId(); sInstance.mPendingAckCountHashMap.put(datagramId, getNumOfListeners()); @@ -356,13 +356,13 @@ public class DatagramReceiver extends Handler { }); sInstance.mControllerMetricsStats.reportIncomingDatagramCount( - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); } if (pendingCount <= 0) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + pendingCount, SatelliteManager.SATELLITE_RESULT_SUCCESS); } else { // Poll for pending datagrams IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { @@ -378,7 +378,7 @@ public class DatagramReceiver extends Handler { // Send the captured data about incoming datagram to metric sInstance.reportMetrics( - satelliteDatagram, SatelliteManager.SATELLITE_ERROR_NONE); + satelliteDatagram, SatelliteManager.SATELLITE_RESULT_SUCCESS); break; } @@ -392,6 +392,10 @@ public class DatagramReceiver extends Handler { case EVENT_RECEIVED_ACK: { DatagramRetryArgument argument = (DatagramRetryArgument) msg.obj; + if (!sInstance.mPendingAckCountHashMap.containsKey(argument.datagramId)) { + logd("The datagram " + argument.datagramId + " should have been deleted."); + return; + } int pendingAckCount = sInstance.mPendingAckCountHashMap .get(argument.datagramId); pendingAckCount -= 1; @@ -424,35 +428,7 @@ public class DatagramReceiver extends Handler { request = (DatagramReceiverHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); - - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance() - .pollPendingSatelliteDatagrams(onCompleted); - break; - } - - Phone phone = request.phone; - if (phone != null) { - phone.pollPendingSatelliteDatagrams(onCompleted); - } else { - loge("pollPendingSatelliteDatagrams: No phone object"); - mDatagramController.updateReceiveStatus(request.subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, - mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - - mDatagramController.updateReceiveStatus(request.subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_ERROR_NONE); - - reportMetrics(null, SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - mControllerMetricsStats.reportIncomingDatagramCount( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - // Send response for current request - ((Consumer<Integer>) request.argument) - .accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + SatelliteModemInterface.getInstance().pollPendingSatelliteDatagrams(onCompleted); break; } @@ -462,7 +438,7 @@ public class DatagramReceiver extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "pollPendingSatelliteDatagrams"); - if (mIsDemoMode && error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (mIsDemoMode && error == SatelliteManager.SATELLITE_RESULT_SUCCESS) { SatelliteDatagram datagram = mDatagramController.getDemoModeDatagram(); final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId( request.subId, mContext); @@ -476,12 +452,12 @@ public class DatagramReceiver extends Handler { ar); listenerHandler.sendMessage(message); } else { - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } } logd("EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE error: " + error); - if (error != SatelliteManager.SATELLITE_ERROR_NONE) { + if (error != SatelliteManager.SATELLITE_RESULT_SUCCESS) { mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), error); @@ -489,7 +465,7 @@ public class DatagramReceiver extends Handler { mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); reportMetrics(null, error); mControllerMetricsStats.reportIncomingDatagramCount(error); @@ -503,6 +479,14 @@ public class DatagramReceiver extends Handler { handleEventSatelliteAlignedTimeout((DatagramReceiverHandlerRequest) msg.obj); break; } + + case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT: + handleEventDatagramWaitForConnectedStateTimedOut(); + break; + + default: + logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); + break; } } @@ -512,12 +496,12 @@ public class DatagramReceiver extends Handler { * @param subId The subId of the subscription to register for incoming satellite datagrams. * @param callback The callback to handle incoming datagrams over satellite. * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. */ - @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { - if (!SatelliteController.getInstance().isSatelliteSupported()) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; + if (!SatelliteController.getInstance().isSatelliteSupportedViaOem()) { + return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); @@ -526,20 +510,14 @@ public class DatagramReceiver extends Handler { if (satelliteDatagramListenerHandler == null) { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mLooper, validSubId); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( - satelliteDatagramListenerHandler, - SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - phone.registerForSatelliteDatagramsReceived(satelliteDatagramListenerHandler, - SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); - } + SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( + satelliteDatagramListenerHandler, + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); } satelliteDatagramListenerHandler.addListener(callback); mSatelliteDatagramListenerHandlers.put(validSubId, satelliteDatagramListenerHandler); - return SatelliteManager.SATELLITE_ERROR_NONE; + return SatelliteManager.SATELLITE_RESULT_SUCCESS; } /** @@ -560,15 +538,8 @@ public class DatagramReceiver extends Handler { if (!handler.hasListeners()) { mSatelliteDatagramListenerHandlers.remove(validSubId); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance() - .unregisterForSatelliteDatagramsReceived(handler); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone != null) { - phone.unregisterForSatelliteDatagramsReceived(handler); - } - } + SatelliteModemInterface.getInstance().unregisterForSatelliteDatagramsReceived( + handler); } } } @@ -582,32 +553,64 @@ public class DatagramReceiver extends Handler { * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback) { if (!mDatagramController.isPollingInIdleState()) { // Poll request should be sent to satellite modem only when it is free. logd("pollPendingSatelliteDatagrams: satellite modem is busy receiving datagrams."); - callback.accept(SatelliteManager.SATELLITE_MODEM_BUSY); + callback.accept(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); return; } - pollPendingSatelliteDatagramsInternal(subId, callback); } + private void handleSatelliteConnectedEvent() { + synchronized (mLock) { + if (isDatagramWaitForConnectedStateTimerStarted()) { + stopDatagramWaitForConnectedStateTimer(); + if (mPendingPollSatelliteDatagramsRequest == null) { + loge("handleSatelliteConnectedEvent: mPendingPollSatelliteDatagramsRequest is" + + " null"); + return; + } + + Consumer<Integer> callback = + (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; + pollPendingSatelliteDatagramsInternal( + mPendingPollSatelliteDatagramsRequest.subId, callback); + mPendingPollSatelliteDatagramsRequest = null; + } + } + } + private void pollPendingSatelliteDatagramsInternal(int subId, @NonNull Consumer<Integer> callback) { if (!mDatagramController.isSendingInIdleState()) { // Poll request should be sent to satellite modem only when it is free. logd("pollPendingSatelliteDatagrams: satellite modem is busy sending datagrams."); - callback.accept(SatelliteManager.SATELLITE_MODEM_BUSY); + callback.accept(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); + return; + } + + if (mDatagramController.needsWaitingForSatelliteConnected()) { + logd("pollPendingSatelliteDatagrams: wait for satellite connected"); + synchronized (mLock) { + mPendingPollSatelliteDatagramsRequest = new DatagramReceiverHandlerRequest( + callback, SatelliteServiceUtils.getPhone(), subId); + mDatagramController.updateReceiveStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_RESULT_SUCCESS); + startDatagramWaitForConnectedStateTimer(); + } return; } mDatagramController.updateReceiveStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); mDatagramTransferStartTime = System.currentTimeMillis(); Phone phone = SatelliteServiceUtils.getPhone(); @@ -641,6 +644,8 @@ public class DatagramReceiver extends Handler { || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { logd("onSatelliteModemStateChanged: cleaning up resources"); cleanUpResources(); + } else if (state == SATELLITE_MODEM_STATE_CONNECTED) { + handleSatelliteConnectedEvent(); } } } @@ -649,31 +654,40 @@ public class DatagramReceiver extends Handler { private void cleanupDemoModeResources() { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); - if (mPollPendingSatelliteDatagramsRequest == null) { + if (mDemoPollPendingSatelliteDatagramsRequest == null) { loge("Satellite aligned timer was started " - + "but mPollPendingSatelliteDatagramsRequest is null"); + + "but mDemoPollPendingSatelliteDatagramsRequest is null"); } else { Consumer<Integer> callback = - (Consumer<Integer>) mPollPendingSatelliteDatagramsRequest.argument; - callback.accept(SatelliteManager.SATELLITE_REQUEST_ABORTED); + (Consumer<Integer>) mDemoPollPendingSatelliteDatagramsRequest.argument; + callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } } mIsDemoMode = false; - mPollPendingSatelliteDatagramsRequest = null; + mDemoPollPendingSatelliteDatagramsRequest = null; mIsAligned = false; } @GuardedBy("mLock") private void cleanUpResources() { + synchronized (mLock) { + if (mPendingPollSatelliteDatagramsRequest != null) { + Consumer<Integer> callback = + (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; + callback.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); + mPendingPollSatelliteDatagramsRequest = null; + } + stopDatagramWaitForConnectedStateTimer(); + } if (mDatagramController.isReceivingDatagrams()) { mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_REQUEST_ABORTED); + SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); } mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); cleanupDemoModeResources(); } @@ -695,7 +709,7 @@ public class DatagramReceiver extends Handler { /** Report incoming datagram related metrics */ private void reportMetrics(@Nullable SatelliteDatagram satelliteDatagram, - @NonNull @SatelliteManager.SatelliteError int resultCode) { + @NonNull @SatelliteManager.SatelliteResult int resultCode) { int datagramSizeRoundedBytes = -1; int datagramTransferTime = 0; @@ -728,7 +742,7 @@ public class DatagramReceiver extends Handler { } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected void onDeviceAlignedWithSatellite(boolean isAligned) { + protected void setDeviceAlignedWithSatellite(boolean isAligned) { if (mIsDemoMode) { synchronized (mLock) { mIsAligned = isAligned; @@ -742,7 +756,7 @@ public class DatagramReceiver extends Handler { logd("Satellite aligned timer was already started"); return; } - mPollPendingSatelliteDatagramsRequest = request; + mDemoPollPendingSatelliteDatagramsRequest = request; sendMessageDelayed( obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request), getSatelliteAlignedTimeoutDuration()); @@ -757,13 +771,14 @@ public class DatagramReceiver extends Handler { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); - if (mPollPendingSatelliteDatagramsRequest == null) { - loge("handleSatelliteAlignedTimer: mPollPendingSatelliteDatagramsRequest is null"); + if (mDemoPollPendingSatelliteDatagramsRequest == null) { + loge("handleSatelliteAlignedTimer: mDemoPollPendingSatelliteDatagramsRequest " + + "is null"); } else { Message message = obtainMessage( EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, - mPollPendingSatelliteDatagramsRequest); - mPollPendingSatelliteDatagramsRequest = null; + mDemoPollPendingSatelliteDatagramsRequest); + mDemoPollPendingSatelliteDatagramsRequest = null; AsyncResult.forMessage(message, null, null); message.sendToTarget(); } @@ -773,7 +788,7 @@ public class DatagramReceiver extends Handler { private void handleEventSatelliteAlignedTimeout(DatagramReceiverHandlerRequest request) { SatelliteManager.SatelliteException exception = new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_NOT_REACHABLE); + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); Message message = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); AsyncResult.forMessage(message, null, exception); message.sendToTarget(); @@ -787,6 +802,55 @@ public class DatagramReceiver extends Handler { removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); } + private void startDatagramWaitForConnectedStateTimer() { + if (isDatagramWaitForConnectedStateTimerStarted()) { + logd("DatagramWaitForConnectedStateTimer is already started"); + return; + } + sendMessageDelayed(obtainMessage( + EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT), + mDatagramController.getDatagramWaitTimeForConnectedState()); + } + + private void stopDatagramWaitForConnectedStateTimer() { + removeMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public boolean isDatagramWaitForConnectedStateTimerStarted() { + return hasMessages(EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT); + } + + private void handleEventDatagramWaitForConnectedStateTimedOut() { + synchronized (mLock) { + if (mPendingPollSatelliteDatagramsRequest == null) { + logw("handleEventDatagramWaitForConnectedStateTimedOut: " + + "mPendingPollSatelliteDatagramsRequest is null"); + return; + } + + logw("Timed out to wait for satellite connected before polling datagrams"); + mDatagramController.updateReceiveStatus(mPendingPollSatelliteDatagramsRequest.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + + mDatagramController.updateReceiveStatus(mPendingPollSatelliteDatagramsRequest.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_RESULT_SUCCESS); + + reportMetrics(null, SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + mControllerMetricsStats.reportIncomingDatagramCount( + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + + Consumer<Integer> callback = + (Consumer<Integer>) mPendingPollSatelliteDatagramsRequest.argument; + callback.accept(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + mPendingPollSatelliteDatagramsRequest = null; + } + } + /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ @@ -802,4 +866,8 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + private static void logw(@NonNull String log) { + Rlog.w(TAG, log); + } } diff --git a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java index 5d4e5dd57f..26100a8314 100644 --- a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java +++ b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java @@ -40,7 +40,7 @@ public class NtnCapabilityResolver { public static void resolveNtnCapability( @NonNull NetworkRegistrationInfo networkRegistrationInfo, int subId) { SatelliteController satelliteController = SatelliteController.getInstance(); - List<String> satellitePlmnList = satelliteController.getSatellitePlmnList(); + List<String> satellitePlmnList = satelliteController.getSatellitePlmnList(subId); String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn(); for (String satellitePlmn : satellitePlmnList) { if (TextUtils.equals(satellitePlmn, registeredPlmn)) { diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index 9dba6f209c..9a6bd695b1 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -16,12 +16,16 @@ package com.android.internal.telephony.satellite; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; @@ -38,9 +42,9 @@ import android.text.TextUtils; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.Phone; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -57,9 +61,12 @@ public class PointingAppController { private static PointingAppController sInstance; @NonNull private final Context mContext; private boolean mStartedSatelliteTransmissionUpdates; + private boolean mLastNeedFullScreenPointingUI; + private boolean mListenerForPointingUIRegistered; @NonNull private String mPointingUiPackageName = ""; @NonNull private String mPointingUiClassName = ""; - + @NonNull private ActivityManager mActivityManager; + @NonNull public UidImportanceListener mUidImportanceListener = new UidImportanceListener(); /** * Map key: subId, value: SatelliteTransmissionUpdateHandler to notify registrants. */ @@ -97,6 +104,9 @@ public class PointingAppController { public PointingAppController(@NonNull Context context) { mContext = context; mStartedSatelliteTransmissionUpdates = false; + mLastNeedFullScreenPointingUI = false; + mListenerForPointingUIRegistered = false; + mActivityManager = mContext.getSystemService(ActivityManager.class); } /** @@ -119,6 +129,36 @@ public class PointingAppController { return mStartedSatelliteTransmissionUpdates; } + /** + * Get the flag mStartedSatelliteTransmissionUpdates + * @return returns mStartedSatelliteTransmissionUpdates + */ + @VisibleForTesting + public boolean getLastNeedFullScreenPointingUI() { + return mLastNeedFullScreenPointingUI; + } + + /** + * Listener for handling pointing UI App in the event of crash + */ + @VisibleForTesting + public class UidImportanceListener implements ActivityManager.OnUidImportanceListener { + @Override + public void onUidImportance(int uid, int importance) { + if (importance != IMPORTANCE_GONE) return; + final PackageManager pm = mContext.getPackageManager(); + final String[] callerPackages = pm.getPackagesForUid(uid); + String pointingUiPackage = getPointingUiPackageName(); + + if (callerPackages != null) { + if (Arrays.stream(callerPackages).anyMatch(pointingUiPackage::contains)) { + logd("Restarting pointingUI"); + startPointingUI(mLastNeedFullScreenPointingUI); + } + } + } + } + private static final class DatagramTransferStateHandlerRequest { public int datagramTransferState; public int pendingCount; @@ -235,31 +275,24 @@ public class PointingAppController { * Register to start receiving updates for satellite position and datagram transfer state * @param subId The subId of the subscription to register for receiving the updates. * @param callback The callback to notify of satellite transmission updates. - * @param phone The Phone object to unregister for receiving the updates. */ public void registerForSatelliteTransmissionUpdates(int subId, - ISatelliteTransmissionUpdateCallback callback, Phone phone) { + ISatelliteTransmissionUpdateCallback callback) { SatelliteTransmissionUpdateHandler handler = mSatelliteTransmissionUpdateHandlers.get(subId); if (handler != null) { handler.addListener(callback); - return; } else { handler = new SatelliteTransmissionUpdateHandler(Looper.getMainLooper()); handler.addListener(callback); mSatelliteTransmissionUpdateHandlers.put(subId, handler); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( - handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, - null); - SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( - handler, - SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, - null); - } else { - phone.registerForSatellitePositionInfoChanged(handler, - SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - } + SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( + handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, + null); + SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( + handler, + SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, + null); } } @@ -269,33 +302,23 @@ public class PointingAppController { * @param subId The subId of the subscription to unregister for receiving the updates. * @param result The callback to get the error code in case of failure * @param callback The callback that was passed to {@link - * #registerForSatelliteTransmissionUpdates(int, ISatelliteTransmissionUpdateCallback, Phone)}. - * @param phone The Phone object to unregister for receiving the updates + * #registerForSatelliteTransmissionUpdates(int, ISatelliteTransmissionUpdateCallback)}. */ public void unregisterForSatelliteTransmissionUpdates(int subId, Consumer<Integer> result, - ISatelliteTransmissionUpdateCallback callback, Phone phone) { + ISatelliteTransmissionUpdateCallback callback) { SatelliteTransmissionUpdateHandler handler = mSatelliteTransmissionUpdateHandlers.get(subId); if (handler != null) { handler.removeListener(callback); if (handler.hasListeners()) { - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS); return; } - mSatelliteTransmissionUpdateHandlers.remove(subId); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().unregisterForSatellitePositionInfoChanged( - handler); - SatelliteModemInterface.getInstance().unregisterForDatagramTransferStateChanged( - handler); - } else { - if (phone == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - phone.unregisterForSatellitePositionInfoChanged(handler); - } + + SatelliteModemInterface satelliteModemInterface = SatelliteModemInterface.getInstance(); + satelliteModemInterface.unregisterForSatellitePositionInfoChanged(handler); + satelliteModemInterface.unregisterForDatagramTransferStateChanged(handler); } } @@ -307,28 +330,16 @@ public class PointingAppController { * {@link android.telephony.satellite.SatelliteTransmissionUpdateCallback * #onSatellitePositionChanged(pointingInfo)}. */ - public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { + public void startSatelliteTransmissionUpdates(@NonNull Message message) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_ERROR_NONE)); + SatelliteManager.SATELLITE_RESULT_SUCCESS)); message.sendToTarget(); return; } - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message); - mStartedSatelliteTransmissionUpdates = true; - return; - } - if (phone != null) { - phone.startSatellitePositionUpdates(message); - mStartedSatelliteTransmissionUpdates = true; - } else { - loge("startSatelliteTransmissionUpdates: No phone object"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); - message.sendToTarget(); - } + SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message); + mStartedSatelliteTransmissionUpdates = true; } /** @@ -336,20 +347,9 @@ public class PointingAppController { * Reset the flag mStartedSatelliteTransmissionUpdates * This can be called by the pointing UI when the user stops pointing to the satellite. */ - public void stopSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { + public void stopSatelliteTransmissionUpdates(@NonNull Message message) { setStartedSatelliteTransmissionUpdates(false); - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message); - return; - } - if (phone != null) { - phone.stopSatellitePositionUpdates(message); - } else { - loge("startSatelliteTransmissionUpdates: No phone object"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); - message.sendToTarget(); - } + SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message); } /** @@ -379,12 +379,28 @@ public class PointingAppController { launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); try { + if (!mListenerForPointingUIRegistered) { + mActivityManager.addOnUidImportanceListener(mUidImportanceListener, + IMPORTANCE_GONE); + mListenerForPointingUIRegistered = true; + } + mLastNeedFullScreenPointingUI = needFullScreenPointingUI; mContext.startActivity(launchIntent); } catch (ActivityNotFoundException ex) { loge("startPointingUI: Pointing UI app activity is not found, ex=" + ex); } } + /** + * Remove the Importance Listener For Pointing UI App once the satellite is disabled + */ + public void removeListenerForPointingUI() { + if (mListenerForPointingUIRegistered) { + mActivityManager.removeOnUidImportanceListener(mUidImportanceListener); + mListenerForPointingUIRegistered = false; + } + } + public void updateSendDatagramTransferState(int subId, @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, int sendPendingCount, int errorCode) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 957b152c25..b4ce9c7d44 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -16,6 +16,18 @@ package com.android.internal.telephony.satellite; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT; +import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER; +import static android.telephony.SubscriptionManager.isValidSubscriptionId; +import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911; +import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH; +import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; + import android.annotation.ArrayRes; import android.annotation.NonNull; import android.annotation.Nullable; @@ -25,7 +37,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.res.Resources; import android.database.ContentObserver; import android.net.wifi.WifiManager; @@ -45,29 +56,39 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; +import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.satellite.INtnSignalStrengthCallback; +import android.telephony.satellite.ISatelliteCapabilitiesCallback; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.uwb.UwbManager; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DeviceStateMonitor; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; @@ -75,7 +96,10 @@ import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -98,6 +122,7 @@ public class SatelliteController extends Handler { /** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */ public static final int SATELLITE_MODE_ENABLED_TRUE = 1; public static final int SATELLITE_MODE_ENABLED_FALSE = 0; + public static final int INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE = -1; /** Message codes used in handleMessage() */ //TODO: Move the Commands and events related to position updates to PointingAppController @@ -127,6 +152,16 @@ public class SatelliteController extends Handler { private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; private static final int EVENT_PENDING_DATAGRAMS = 27; private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; + private static final int EVENT_SET_SATELLITE_PLMN_INFO_DONE = 29; + private static final int CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE = 30; + private static final int EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE = 31; + private static final int CMD_REQUEST_NTN_SIGNAL_STRENGTH = 32; + private static final int EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE = 33; + private static final int EVENT_NTN_SIGNAL_STRENGTH_CHANGED = 34; + private static final int CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING = 35; + private static final int EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE = 36; + private static final int EVENT_SERVICE_STATE_CHANGED = 37; + private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -136,13 +171,14 @@ public class SatelliteController extends Handler { @NonNull private final DatagramController mDatagramController; @NonNull private final ControllerMetricsStats mControllerMetricsStats; @NonNull private final ProvisionMetricsStats mProvisionMetricsStats; - private SharedPreferences mSharedPreferences = null; + @NonNull private final SubscriptionManagerService mSubscriptionManagerService; private final CommandsInterface mCi; - private ContentResolver mContentResolver = null; + private ContentResolver mContentResolver; + private final DeviceStateMonitor mDSM; private final Object mRadioStateLock = new Object(); - /** Flags to indicate whether the resepective radio is enabled */ + /** Flags to indicate whether the respective radio is enabled */ @GuardedBy("mRadioStateLock") private boolean mBTStateEnabled = false; @GuardedBy("mRadioStateLock") @@ -172,16 +208,14 @@ public class SatelliteController extends Handler { private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = - new AtomicBoolean(false); private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = - new AtomicBoolean(false); private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = + private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForSatelliteCapabilitiesChanged = new AtomicBoolean(false); + private final AtomicBoolean mShouldReportNtnSignalStrength = new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -193,6 +227,18 @@ public class SatelliteController extends Handler { */ private final ConcurrentHashMap<IBinder, ISatelliteProvisionStateCallback> mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); + /** + * Map key: binder of the callback, value: callback to receive non-terrestrial signal strength + * state changed events. + */ + private final ConcurrentHashMap<IBinder, INtnSignalStrengthCallback> + mNtnSignalStrengthChangedListeners = new ConcurrentHashMap<>(); + /** + * Map key: binder of the callback, value: callback to receive satellite capabilities changed + * events. + */ + private final ConcurrentHashMap<IBinder, ISatelliteCapabilitiesCallback> + mSatelliteCapabilitiesChangedListeners = new ConcurrentHashMap<>(); private final Object mIsSatelliteSupportedLock = new Object(); @GuardedBy("mIsSatelliteSupportedLock") private Boolean mIsSatelliteSupported = null; @@ -210,22 +256,59 @@ public class SatelliteController extends Handler { private final Object mNeedsSatellitePointingLock = new Object(); @GuardedBy("mNeedsSatellitePointingLock") private boolean mNeedsSatellitePointing = false; + private final Object mNtnSignalsStrengthLock = new Object(); + @GuardedBy("mNtnSignalsStrengthLock") + private NtnSignalStrength mNtnSignalStrength = + new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE); /** Key: subId, value: (key: PLMN, value: set of * {@link android.telephony.NetworkRegistrationInfo.ServiceType}) */ @GuardedBy("mSupportedSatelliteServicesLock") - @NonNull private final Map<Integer, Map<String, Set<Integer>>> mSupportedSatelliteServices = - new HashMap<>(); + @NonNull private final Map<Integer, Map<String, Set<Integer>>> + mSatelliteServicesSupportedByCarriers = new HashMap<>(); @NonNull private final Object mSupportedSatelliteServicesLock = new Object(); - /** Key: PLMN, value: set of {@link android.telephony.NetworkRegistrationInfo.ServiceType} */ - @NonNull private final Map<String, Set<Integer>> mSatelliteServicesSupportedByProviders; + @NonNull private final List<String> mSatellitePlmnListFromOverlayConfig; @NonNull private final CarrierConfigManager mCarrierConfigManager; @NonNull private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @NonNull private final Object mCarrierConfigArrayLock = new Object(); @GuardedBy("mCarrierConfigArrayLock") @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>(); - @NonNull private final List<String> mSatellitePlmnList; + @GuardedBy("mIsSatelliteEnabledLock") + /** Key: Subscription ID, value: set of restriction reasons for satellite communication.*/ + @NonNull private final Map<Integer, Set<Integer>> mSatelliteAttachRestrictionForCarrierArray = + new HashMap<>(); + @GuardedBy("mIsSatelliteEnabledLock") + /** Key: Subscription ID, value: the actual satellite enabled state in the modem - + * {@code true} for enabled and {@code false} for disabled. */ + @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub = + new HashMap<>(); + @NonNull private final FeatureFlags mFeatureFlags; + @NonNull private final Object mSatelliteConnectedLock = new Object(); + /** Key: Subscription ID; Value: Last satellite connected time */ + @GuardedBy("mSatelliteConnectedLock") + @NonNull private final SparseArray<Long> mLastSatelliteDisconnectedTimesMillis = + new SparseArray<>(); + /** + * Key: Subscription ID; Value: {@code true} if satellite was just connected, + * {@code false} otherwise. + */ + @GuardedBy("mSatelliteConnectedLock") + @NonNull private final SparseBooleanArray + mWasSatelliteConnectedViaCarrier = new SparseBooleanArray(); + + @GuardedBy("mSatelliteConnectedLock") + @NonNull private final SparseBooleanArray + mIsSatelliteConnectedViaCarrierHysteresisTimeExpired = new SparseBooleanArray(); + + /** + * This is used for testing only. When mEnforcedEmergencyCallToSatelliteHandoverType is valid, + * Telephony will ignore the IMS registration status and cellular availability, and always send + * the connection event EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer. + */ + private int mEnforcedEmergencyCallToSatelliteHandoverType = + INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; + private int mDelayInSendingEventDisplayEmergencyMessage = 0; /** * @return The singleton instance of SatelliteController. @@ -240,12 +323,13 @@ public class SatelliteController extends Handler { /** * Create the SatelliteController singleton instance. * @param context The Context to use to create the SatelliteController. + * @param featureFlags The feature flag. */ - public static void make(@NonNull Context context) { + public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) { if (sInstance == null) { HandlerThread satelliteThread = new HandlerThread(TAG); satelliteThread.start(); - sInstance = new SatelliteController(context, satelliteThread.getLooper()); + sInstance = new SatelliteController(context, satelliteThread.getLooper(), featureFlags); } } @@ -255,14 +339,18 @@ public class SatelliteController extends Handler { * * @param context The Context for the SatelliteController. * @param looper The looper for the handler. It does not run on main thread. + * @param featureFlags The feature flag. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public SatelliteController(@NonNull Context context, @NonNull Looper looper) { + public SatelliteController( + @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) { super(looper); mContext = context; + mFeatureFlags = featureFlags; Phone phone = SatelliteServiceUtils.getPhone(); mCi = phone.mCi; + mDSM = phone.getDeviceStateMonitor(); // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); @@ -275,6 +363,7 @@ public class SatelliteController extends Handler { // should be called before making DatagramController mControllerMetricsStats = ControllerMetricsStats.make(mContext); mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance(); + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); // Create the DatagramController singleton, // which is used to send and receive satellite datagrams. @@ -292,16 +381,10 @@ public class SatelliteController extends Handler { registerForSatelliteProvisionStateChanged(); registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); + registerForServiceStateChanged(); mContentResolver = mContext.getContentResolver(); mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); - try { - mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, - Context.MODE_PRIVATE); - } catch (Exception e) { - loge("Cannot get default shared preferences: " + e); - } - initializeSatelliteModeRadios(); ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) { @@ -316,15 +399,15 @@ public class SatelliteController extends Handler { false, satelliteModeRadiosContentObserver); } - mSatelliteServicesSupportedByProviders = readSupportedSatelliteServicesFromOverlayConfig(); - mSatellitePlmnList = - mSatelliteServicesSupportedByProviders.keySet().stream().toList(); + mSatellitePlmnListFromOverlayConfig = readSatellitePlmnsFromOverlayConfig(); updateSupportedSatelliteServicesForActiveSubscriptions(); mCarrierConfigChangeListener = (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId); mCarrierConfigManager.registerCarrierConfigChangeListener( new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener); + mDSM.registerForSignalStrengthReportDecision(this, CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING, + null); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @@ -541,6 +624,21 @@ public class SatelliteController extends Handler { } } + private static final class RequestHandleSatelliteAttachRestrictionForCarrierArgument { + public int subId; + @SatelliteManager.SatelliteCommunicationRestrictionReason + public int reason; + @NonNull public Consumer<Integer> callback; + + RequestHandleSatelliteAttachRestrictionForCarrierArgument(int subId, + @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, + Consumer<Integer> callback) { + this.subId = subId; + this.reason = reason; + this.callback = callback; + } + } + private static final class ProvisionSatelliteServiceArgument { @NonNull public String token; @NonNull public byte[] provisionData; @@ -583,8 +681,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request); - mPointingAppController.startSatelliteTransmissionUpdates(onCompleted, - request.phone); + mPointingAppController.startSatelliteTransmissionUpdates(onCompleted); break; } @@ -597,7 +694,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request); - mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted, request.phone); + mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted); break; } @@ -616,7 +713,7 @@ public class SatelliteController extends Handler { (ProvisionSatelliteServiceArgument) request.argument; if (mSatelliteProvisionCallbacks.containsKey(argument.subId)) { argument.callback.accept( - SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); + SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS); notifyRequester(request); break; } @@ -624,24 +721,8 @@ public class SatelliteController extends Handler { onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request); // Log the current time for provision triggered mProvisionMetricsStats.setProvisioningStartTime(); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.provisionSatelliteService(argument.token, - argument.provisionData, onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.provisionSatelliteService(onCompleted, argument.token); - } else { - loge("provisionSatelliteService: No phone object"); - argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - notifyRequester(request); - mProvisionMetricsStats - .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) - .reportProvisionMetrics(); - mControllerMetricsStats.reportProvisionCount( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + mSatelliteModemInterface.provisionSatelliteService(argument.token, + argument.provisionData, onCompleted); break; } @@ -664,26 +745,7 @@ public class SatelliteController extends Handler { if (argument.callback != null) { mProvisionMetricsStats.setProvisioningStartTime(); } - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .deprovisionSatelliteService(argument.token, onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.deprovisionSatelliteService(onCompleted, argument.token); - } else { - loge("deprovisionSatelliteService: No phone object"); - if (argument.callback != null) { - argument.callback.accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - mProvisionMetricsStats - .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) - .reportProvisionMetrics(); - mControllerMetricsStats.reportDeprovisionCount( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } - } + mSatelliteModemInterface.deprovisionSatelliteService(argument.token, onCompleted); break; } @@ -711,7 +773,7 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled"); logd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (argument.enableSatellite) { synchronized (mSatelliteEnabledRequestLock) { mWaitingForRadioDisabled = true; @@ -726,6 +788,13 @@ public class SatelliteController extends Handler { } evaluateToSendSatelliteEnabledSuccess(); } else { + /** + * Unregister Importance Listener for Pointing UI + * when Satellite is disabled + */ + if (mNeedsSatellitePointing) { + mPointingAppController.removeListenerForPointingUI(); + } synchronized (mSatelliteEnabledRequestLock) { if (mSatelliteEnabledRequest != null && mSatelliteEnabledRequest.enableSatellite == true && @@ -733,14 +802,15 @@ public class SatelliteController extends Handler { // Previous mSatelliteEnabledRequest is successful but waiting for // all radios to be turned off. mSatelliteEnabledRequest.callback.accept( - SatelliteManager.SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); } } synchronized (mIsSatelliteEnabledLock) { if (!mWaitingForSatelliteModemOff) { moveSatelliteToOffStateAndCleanUpResources( - SatelliteManager.SATELLITE_ERROR_NONE, argument.callback); + SATELLITE_RESULT_SUCCESS, + argument.callback); } else { logd("Wait for satellite modem off before updating satellite" + " modem state"); @@ -756,7 +826,7 @@ public class SatelliteController extends Handler { // Previous mSatelliteEnabledRequest is successful but waiting for // all radios to be turned off. mSatelliteEnabledRequest.callback.accept( - SatelliteManager.SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); } } resetSatelliteEnabledRequest(); @@ -766,7 +836,7 @@ public class SatelliteController extends Handler { } if (argument.enableSatellite) { - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { mControllerMetricsStats.onSatelliteEnabled(); mControllerMetricsStats.reportServiceEnablementSuccessCount(); } else { @@ -774,7 +844,7 @@ public class SatelliteController extends Handler { } SessionMetricsStats.getInstance() .setInitializationResult(error) - .setRadioTechnology(SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY) + .setRadioTechnology(getSupportedNtnRadioTechnology()) .reportSessionMetrics(); } else { mControllerMetricsStats.onSatelliteDisabled(); @@ -788,18 +858,7 @@ public class SatelliteController extends Handler { case CMD_IS_SATELLITE_ENABLED: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatellitePowerOn(onCompleted); - } else { - loge("isSatelliteEnabled: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted); break; } @@ -809,17 +868,17 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteEnabled"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("isSatelliteEnabled: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } - } else if (error == SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED) { + } else if (error == SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) { updateSatelliteSupportedStateWhenSatelliteServiceConnected(false); } ((ResultReceiver) request.argument).send(error, bundle); @@ -829,19 +888,7 @@ public class SatelliteController extends Handler { case CMD_IS_SATELLITE_SUPPORTED: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request); - - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteSupported(onCompleted); - } else { - loge("isSatelliteSupported: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted); break; } @@ -850,10 +897,10 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("isSatelliteSupported: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); @@ -868,18 +915,7 @@ public class SatelliteController extends Handler { case CMD_GET_SATELLITE_CAPABILITIES: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.getSatelliteCapabilities(onCompleted); - } else { - loge("getSatelliteCapabilities: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted); break; } @@ -889,10 +925,10 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "getSatelliteCapabilities"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("getSatelliteCapabilities: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; synchronized (mNeedsSatellitePointingLock) { @@ -914,20 +950,8 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .requestIsSatelliteCommunicationAllowedForCurrentLocation( - onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteCommunicationAllowedForCurrentLocation(onCompleted); - } else { - loge("isSatelliteCommunicationAllowedForCurrentLocation: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface + .requestIsSatelliteCommunicationAllowedForCurrentLocation(onCompleted); break; } @@ -937,10 +961,10 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteCommunicationAllowedForCurrentLocation"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("isSatelliteCommunicationAllowedForCurrentLocation: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { boolean communicationAllowed = (boolean) ar.result; if (DBG) { @@ -959,19 +983,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .requestTimeForNextSatelliteVisibility(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.requestTimeForNextSatelliteVisibility(onCompleted); - } else { - loge("requestTimeForNextSatelliteVisibility: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface.requestTimeForNextSatelliteVisibility(onCompleted); break; } @@ -981,10 +993,10 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "requestTimeForNextSatelliteVisibility"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("requestTimeForNextSatelliteVisibility: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { int nextVisibilityDuration = ((int[]) ar.result)[0]; if (DBG) { @@ -1000,29 +1012,7 @@ public class SatelliteController extends Handler { } case EVENT_RADIO_STATE_CHANGED: { - if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF - || mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE) { - mIsRadioOn = false; - logd("Radio State Changed to " + mCi.getRadioState()); - if (isSatelliteEnabled()) { - IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("RequestSatelliteEnabled: result=" + result); - } - }; - Phone phone = SatelliteServiceUtils.getPhone(); - Consumer<Integer> result = FunctionalUtils - .ignoreRemoteException(errorCallback::accept); - RequestSatelliteEnabledArgument message = - new RequestSatelliteEnabledArgument(false, false, result); - request = new SatelliteControllerHandlerRequest(message, phone); - handleSatelliteEnabled(request); - } else { - logd("EVENT_RADIO_STATE_CHANGED: Satellite modem is currently disabled." - + " Ignored the event"); - } - } else { + if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { mIsRadioOn = true; if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { synchronized (mIsSatelliteSupportedLock) { @@ -1039,9 +1029,6 @@ public class SatelliteController extends Handler { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); } } - } else { - logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." - + " Ignored the event"); } } break; @@ -1050,18 +1037,7 @@ public class SatelliteController extends Handler { case CMD_IS_SATELLITE_PROVISIONED: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteProvisioned(onCompleted); - } else { - loge("isSatelliteProvisioned: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } + mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); break; } @@ -1071,10 +1047,10 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteProvisioned"); Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (error == SATELLITE_RESULT_SUCCESS) { if (ar.result == null) { loge("isSatelliteProvisioned: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } else { boolean provisioned = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteProvisioned: " + provisioned); @@ -1118,6 +1094,153 @@ public class SatelliteController extends Handler { } break; + case EVENT_SET_SATELLITE_PLMN_INFO_DONE: + handleSetSatellitePlmnInfoDoneEvent(msg); + break; + + case CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE: { + logd("CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE"); + request = (SatelliteControllerHandlerRequest) msg.obj; + handleRequestSatelliteAttachRestrictionForCarrierCmd(request); + break; + } + + case EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + RequestHandleSatelliteAttachRestrictionForCarrierArgument argument = + (RequestHandleSatelliteAttachRestrictionForCarrierArgument) + request.argument; + int subId = argument.subId; + int error = SatelliteServiceUtils.getSatelliteError(ar, + "requestSetSatelliteEnabledForCarrier"); + + synchronized (mIsSatelliteEnabledLock) { + if (error == SATELLITE_RESULT_SUCCESS) { + boolean enableSatellite = mSatelliteAttachRestrictionForCarrierArray + .getOrDefault(argument.subId, Collections.emptySet()).isEmpty(); + mIsSatelliteAttachEnabledForCarrierArrayPerSub.put(subId, enableSatellite); + } else { + mIsSatelliteAttachEnabledForCarrierArrayPerSub.remove(subId); + } + } + + argument.callback.accept(error); + break; + } + + case CMD_REQUEST_NTN_SIGNAL_STRENGTH: { + logd("CMD_REQUEST_NTN_SIGNAL_STRENGTH"); + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE, request); + mSatelliteModemInterface.requestNtnSignalStrength(onCompleted); + break; + } + + case EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + ResultReceiver result = (ResultReceiver) request.argument; + int errorCode = SatelliteServiceUtils.getSatelliteError(ar, + "requestNtnSignalStrength"); + if (errorCode == SATELLITE_RESULT_SUCCESS) { + NtnSignalStrength ntnSignalStrength = (NtnSignalStrength) ar.result; + if (ntnSignalStrength != null) { + synchronized (mNtnSignalsStrengthLock) { + mNtnSignalStrength = ntnSignalStrength; + } + Bundle bundle = new Bundle(); + bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, ntnSignalStrength); + result.send(SATELLITE_RESULT_SUCCESS, bundle); + } else { + synchronized (mNtnSignalsStrengthLock) { + if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) { + mNtnSignalStrength = new NtnSignalStrength( + NTN_SIGNAL_STRENGTH_NONE); + } + } + loge("EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: ntnSignalStrength is null"); + result.send(SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED, null); + } + } else { + synchronized (mNtnSignalsStrengthLock) { + if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) { + mNtnSignalStrength = new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE); + } + } + result.send(errorCode, null); + } + break; + } + + case EVENT_NTN_SIGNAL_STRENGTH_CHANGED: { + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_NTN_SIGNAL_STRENGTH_CHANGED: result is null"); + } else { + handleEventNtnSignalStrengthChanged((NtnSignalStrength) ar.result); + } + break; + } + + case CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: { + ar = (AsyncResult) msg.obj; + boolean shouldReport = (boolean) ar.result; + if (DBG) { + logd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: shouldReport=" + shouldReport); + } + request = new SatelliteControllerHandlerRequest(shouldReport, + SatelliteServiceUtils.getPhone()); + if (SATELLITE_RESULT_SUCCESS != evaluateOemSatelliteRequestAllowed(true)) { + return; + } + if (mShouldReportNtnSignalStrength.get() == shouldReport) { + if (DBG) { + logd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING : modem state matches the " + + "expected state, return."); + } + return; + } + onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE, + request); + if (shouldReport) { + mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted); + } else { + mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted); + } + break; + } + + case EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + boolean shouldReport = (boolean) request.argument; + int errorCode = SatelliteServiceUtils.getSatelliteError(ar, + "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE"); + if (errorCode == SATELLITE_RESULT_SUCCESS) { + mShouldReportNtnSignalStrength.set(shouldReport); + } else { + loge(((boolean) request.argument ? "startSendingNtnSignalStrength" + : "stopSendingNtnSignalStrength") + "returns " + errorCode); + } + break; + } + + case EVENT_SERVICE_STATE_CHANGED: { + handleEventServiceStateChanged(); + break; + } + + case EVENT_SATELLITE_CAPABILITIES_CHANGED: { + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_SATELLITE_CAPABILITIES_CHANGED: result is null"); + } else { + handleEventSatelliteCapabilitiesChanged((SatelliteCapabilities) ar.result); + } + break; + } + default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -1146,33 +1269,18 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { logd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite + " enableDemoMode: " + enableDemoMode); - Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); - - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); - return; - } - - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + sendErrorAndReportSessionMetrics(error, result); return; } if (enableSatellite) { if (!mIsRadioOn) { loge("Radio is not on, can not enable satellite"); - result.accept(SatelliteManager.SATELLITE_INVALID_MODEM_STATE); + sendErrorAndReportSessionMetrics( + SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result); return; } } else { @@ -1186,12 +1294,14 @@ public class SatelliteController extends Handler { if (enableDemoMode != mIsDemoModeEnabled) { loge("Received invalid demo mode while satellite session is enabled" + " enableDemoMode = " + enableDemoMode); - result.accept(SatelliteManager.SATELLITE_INVALID_ARGUMENTS); + sendErrorAndReportSessionMetrics( + SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS, result); return; } else { logd("Enable request matches with current state" + " enableSatellite = " + enableSatellite); - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + sendErrorAndReportSessionMetrics( + SatelliteManager.SATELLITE_RESULT_SUCCESS, result); return; } } @@ -1206,7 +1316,8 @@ public class SatelliteController extends Handler { * 2. If there is a ongoing request, then: * 1. ongoing request = enable, current request = enable: return IN_PROGRESS error * 2. ongoing request = disable, current request = disable: return IN_PROGRESS error - * 3. ongoing request = disable, current request = enable: return SATELLITE_ERROR error + * 3. ongoing request = disable, current request = enable: return + * SATELLITE_RESULT_ERROR error * 4. ongoing request = enable, current request = disable: send request to modem */ synchronized (mSatelliteEnabledRequestLock) { @@ -1215,18 +1326,20 @@ public class SatelliteController extends Handler { } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) { logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " is already in progress."); - result.accept(SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS); + sendErrorAndReportSessionMetrics( + SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS, result); return; } else if (mSatelliteEnabledRequest.enableSatellite == false && request.enableSatellite == true) { logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " cannot be " + "processed. Disable satellite is already in progress."); - result.accept(SatelliteManager.SATELLITE_ERROR); + sendErrorAndReportSessionMetrics( + SatelliteManager.SATELLITE_RESULT_ERROR, result); return; } } - sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null); } /** @@ -1237,13 +1350,9 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } @@ -1252,12 +1361,12 @@ public class SatelliteController extends Handler { /* We have already successfully queried the satellite modem. */ Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, mIsSatelliteEnabled); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SATELLITE_RESULT_SUCCESS, bundle); return; } } - sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, null); } /** @@ -1267,6 +1376,10 @@ public class SatelliteController extends Handler { * @return {@code true} if the satellite modem is enabled and {@code false} otherwise. */ public boolean isSatelliteEnabled() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("isSatelliteEnabled: oemEnabledSatelliteFlag is disabled"); + return false; + } if (mIsSatelliteEnabled == null) return false; return mIsSatelliteEnabled; } @@ -1280,29 +1393,15 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); - return; - } - - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } final Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SATELLITE_RESULT_SUCCESS, bundle); } /** @@ -1311,6 +1410,10 @@ public class SatelliteController extends Handler { * @return {@code true} if the satellite demo mode is enabled and {@code false} otherwise. */ public boolean isDemoModeEnabled() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("isDemoModeEnabled: oemEnabledSatelliteFlag is disabled"); + return false; + } return mIsDemoModeEnabled; } @@ -1322,17 +1425,22 @@ public class SatelliteController extends Handler { * the device if the request is successful or an error code if the request failed. */ public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("requestIsSatelliteSupported: oemEnabledSatelliteFlag is disabled"); + result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null); + return; + } synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported != null) { /* We have already successfully queried the satellite modem. */ Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SATELLITE_RESULT_SUCCESS, bundle); return; } } - sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, null); } /** @@ -1343,13 +1451,9 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } @@ -1358,12 +1462,12 @@ public class SatelliteController extends Handler { Bundle bundle = new Bundle(); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, mSatelliteCapabilities); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SATELLITE_RESULT_SUCCESS, bundle); return; } } - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, null); } /** @@ -1379,31 +1483,16 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); - return; - } - - Phone phone = SatelliteServiceUtils.getPhone(); final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); + mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, - new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); + new SatelliteTransmissionUpdateArgument(result, callback, validSubId), null); } /** @@ -1418,35 +1507,20 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); - return; - } - - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return; } - Phone phone = SatelliteServiceUtils.getPhone(); final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( - validSubId, result, callback, phone); + validSubId, result, callback); // Even if handler is null - which means there are no listeners, the modem command to stop // satellite transmission updates might have failed. The callers might want to retry // sending the command. Thus, we always need to send this command to the modem. - sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, phone); + sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, null); } /** @@ -1466,38 +1540,33 @@ public class SatelliteController extends Handler { @NonNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return null; - } - if (!satelliteSupported) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { - result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); + result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS); return null; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); + Boolean satelliteProvisioned = isSatelliteViaOemProvisioned(); if (satelliteProvisioned != null && satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + result.accept(SATELLITE_RESULT_SUCCESS); return null; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId), - phone); + null); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> { sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, provisionData, null, - validSubId), phone); + validSubId), null); mProvisionMetricsStats.setIsCanceled(true); }); return cancelTransport; @@ -1517,31 +1586,26 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); + Boolean satelliteProvisioned = isSatelliteViaOemProvisioned(); if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE); return; } if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + result.accept(SATELLITE_RESULT_SUCCESS); return; } - Phone phone = SatelliteServiceUtils.getPhone(); final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), - phone); + null); } /** @@ -1550,20 +1614,17 @@ public class SatelliteController extends Handler { * @param subId The subId of the subscription to register for provision state changed. * @param callback The callback to handle the satellite provision state changed event. * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. */ - @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, - @NonNull ISatelliteProvisionStateCallback callback) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - if (!satelliteSupported) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; + @SatelliteManager.SatelliteResult public int registerForSatelliteProvisionStateChanged( + int subId, @NonNull ISatelliteProvisionStateCallback callback) { + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + return error; } mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); - return SatelliteManager.SATELLITE_ERROR_NONE; + return SATELLITE_RESULT_SUCCESS; } /** @@ -1576,6 +1637,11 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("unregisterForSatelliteProvisionStateChanged: " + + "oemEnabledSatelliteFlag is disabled"); + return; + } mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); } @@ -1588,13 +1654,9 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } @@ -1603,12 +1665,12 @@ public class SatelliteController extends Handler { Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, mIsSatelliteProvisioned); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SATELLITE_RESULT_SUCCESS, bundle); return; } } - sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, null); } /** @@ -1617,18 +1679,22 @@ public class SatelliteController extends Handler { * @param subId The subId of the subscription to register for satellite modem state changed. * @param callback The callback to handle the satellite modem state changed event. * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. */ - @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId, + @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("registerForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled"); + return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; + } if (mSatelliteSessionController != null) { mSatelliteSessionController.registerForSatelliteModemStateChanged(callback); } else { loge("registerForSatelliteModemStateChanged: mSatelliteSessionController" + " is not initialized yet"); - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; } - return SatelliteManager.SATELLITE_ERROR_NONE; + return SATELLITE_RESULT_SUCCESS; } /** @@ -1641,6 +1707,10 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("unregisterForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled"); + return; + } if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1655,10 +1725,18 @@ public class SatelliteController extends Handler { * @param subId The subId of the subscription to register for incoming satellite datagrams. * @param callback The callback to handle incoming datagrams over satellite. * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. */ - @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("registerForSatelliteDatagram: oemEnabledSatelliteFlag is disabled"); + return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; + } + if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { + return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; + } + logd("registerForSatelliteDatagram: callback=" + callback); return mDatagramController.registerForSatelliteDatagram(subId, callback); } @@ -1672,6 +1750,14 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("unregisterForSatelliteDatagram: oemEnabledSatelliteFlag is disabled"); + return; + } + if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { + return; + } + logd("unregisterForSatelliteDatagram: callback=" + callback); mDatagramController.unregisterForSatelliteDatagram(subId, callback); } @@ -1684,18 +1770,13 @@ public class SatelliteController extends Handler { * long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); - - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return; } @@ -1717,20 +1798,15 @@ public class SatelliteController extends Handler { * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request. */ public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull IIntegerConsumer callback) { Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); - - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.accept(error); return; } @@ -1757,18 +1833,13 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + int error = evaluateOemSatelliteRequestAllowed(false); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } - sendRequestAsync( - CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, null); } /** @@ -1779,38 +1850,242 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupportedInternal(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); return; } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + + sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, null); + } + + /** + * Inform whether the device is aligned with satellite for demo mode. + * + * @param subId The subId of the subscription. + * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}. + */ + public void setDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setDeviceAlignedWithSatellite: oemEnabledSatelliteFlag is disabled"); return; } + mDatagramController.setDeviceAlignedWithSatellite(isAligned); + } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + /** + * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach + * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled, + * and request modem to enable/disable satellite accordingly if the desired state does not match + * the current state. + * + * @param subId The subId of the subscription to request for. + * @param reason Reason for disallowing satellite communication for carrier. + * @param callback The callback to get the result of the request. + */ + public void addSatelliteAttachRestrictionForCarrier(int subId, + @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, + @NonNull IIntegerConsumer callback) { + if (DBG) logd("addSatelliteAttachRestrictionForCarrier(" + subId + ", " + reason + ")"); + Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + logd("addSatelliteAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is " + + "disabled"); return; } - if (!satelliteProvisioned) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + + synchronized (mIsSatelliteEnabledLock) { + if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault( + subId, Collections.emptySet()).isEmpty()) { + mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>()); + } else if (mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) { + result.accept(SATELLITE_RESULT_SUCCESS); + return; + } + mSatelliteAttachRestrictionForCarrierArray.get(subId).add(reason); + } + RequestHandleSatelliteAttachRestrictionForCarrierArgument request = + new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason, + result); + sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request, + SatelliteServiceUtils.getPhone(subId)); + } + + /** + * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach + * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled, + * and request modem to enable/disable satellite accordingly if the desired state does not match + * the current state. + * + * @param subId The subId of the subscription to request for. + * @param reason Reason for disallowing satellite communication. + * @param callback The callback to get the result of the request. + */ + public void removeSatelliteAttachRestrictionForCarrier(int subId, + @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, + @NonNull IIntegerConsumer callback) { + if (DBG) logd("removeSatelliteAttachRestrictionForCarrier(" + subId + ", " + reason + ")"); + Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + logd("removeSatelliteAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is " + + "disabled"); return; } + synchronized (mIsSatelliteEnabledLock) { + if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault( + subId, Collections.emptySet()).isEmpty() + || !mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) { + result.accept(SATELLITE_RESULT_SUCCESS); + return; + } + mSatelliteAttachRestrictionForCarrierArray.get(subId).remove(reason); + } + RequestHandleSatelliteAttachRestrictionForCarrierArgument request = + new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason, + result); + sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request, + SatelliteServiceUtils.getPhone(subId)); + } + + /** + * Get reasons for disallowing satellite communication, as requested by + * {@link #addSatelliteAttachRestrictionForCarrier(int, int, IIntegerConsumer)}. + * + * @param subId The subId of the subscription to request for. + * + * @return Set of reasons for disallowing satellite attach for carrier. + */ + @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("getSatelliteAttachRestrictionReasonsForCarrier: carrierEnabledSatelliteFlag is " + + "disabled"); + return new HashSet<>(); + } + synchronized (mIsSatelliteEnabledLock) { + Set<Integer> resultSet = + mSatelliteAttachRestrictionForCarrierArray.get(subId); + if (resultSet == null) { + return new HashSet<>(); + } + return new HashSet<>(resultSet); + } + } + + /** + * Request to get the signal strength of the satellite connection. + * + * @param subId The subId of the subscription to request for. + * @param result Result receiver to get the error code of the request and the current signal + * strength of the satellite connection. + */ + public void requestNtnSignalStrength(int subId, @NonNull ResultReceiver result) { + if (DBG) logd("requestNtnSignalStrength()"); + + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) { + result.send(error, null); + return; + } + + /* In case cache is available, it is not needed to request non-terrestrial signal strength + to modem */ + synchronized (mNtnSignalsStrengthLock) { + if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) { + Bundle bundle = new Bundle(); + bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, mNtnSignalStrength); + result.send(SATELLITE_RESULT_SUCCESS, bundle); + return; + } + } + Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); + sendRequestAsync(CMD_REQUEST_NTN_SIGNAL_STRENGTH, result, phone); } /** - * Inform whether the device is aligned with satellite for demo mode. + * Registers for NTN signal strength changed from satellite modem. If the registration operation + * is not successful, a {@link ServiceSpecificException} that contains + * {@link SatelliteManager.SatelliteResult} will be thrown. * - * @param subId The subId of the subscription. - * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}. + * @param subId The id of the subscription to request for. + * @param callback The callback to handle the NTN signal strength changed event. If the + * operation is successful, {@link INtnSignalStrengthCallback#onNtnSignalStrengthChanged( + * NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of + * {@link NtnSignalStrength.NtnSignalStrengthLevel} when the signal strength of non-terrestrial + * network has changed. + * + * @throws ServiceSpecificException If the callback registration operation fails. + */ + public void registerForNtnSignalStrengthChanged(int subId, + @NonNull INtnSignalStrengthCallback callback) throws RemoteException { + if (DBG) logd("registerForNtnSignalStrengthChanged()"); + + int error = evaluateOemSatelliteRequestAllowed(true); + if (error == SATELLITE_RESULT_SUCCESS) { + mNtnSignalStrengthChangedListeners.put(callback.asBinder(), callback); + } else { + throw new ServiceSpecificException(error); + } + } + + /** + * Unregisters for NTN signal strength changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param subId The id of the subscription to unregister for listening NTN signal strength + * changed event. + * @param callback The callback that was passed to + * {@link #registerForNtnSignalStrengthChanged(int, INtnSignalStrengthCallback)} */ - public void onDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) { - mDatagramController.onDeviceAlignedWithSatellite(isAligned); + public void unregisterForNtnSignalStrengthChanged( + int subId, @NonNull INtnSignalStrengthCallback callback) { + if (DBG) logd("unregisterForNtnSignalStrengthChanged()"); + + int error = evaluateOemSatelliteRequestAllowed(true); + if (error == SATELLITE_RESULT_SUCCESS) { + mNtnSignalStrengthChangedListeners.remove(callback.asBinder()); + } + } + + /** + * Registers for satellite capabilities change event from the satellite service. + * + * @param subId The id of the subscription to request for. + * @param callback The callback to handle the satellite capabilities changed event. + * + * @return The {@link SatelliteManager.SatelliteResult} result of the operation. + */ + @SatelliteManager.SatelliteResult public int registerForSatelliteCapabilitiesChanged( + int subId, @NonNull ISatelliteCapabilitiesCallback callback) { + if (DBG) logd("registerForSatelliteCapabilitiesChanged()"); + + int error = evaluateOemSatelliteRequestAllowed(true); + if (error != SATELLITE_RESULT_SUCCESS) return error; + + mSatelliteCapabilitiesChangedListeners.put(callback.asBinder(), callback); + return SATELLITE_RESULT_SUCCESS; + } + + /** + * Unregisters for satellite capabilities change event from the satellite service. + * If callback was not registered before, the request will be ignored. + * + * @param subId The id of the subscription to unregister for listening satellite capabilities + * changed event. + * @param callback The callback that was passed to + * {@link #registerForSatelliteCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)} + */ + public void unregisterForSatelliteCapabilitiesChanged( + int subId, @NonNull ISatelliteCapabilitiesCallback callback) { + if (DBG) logd("unregisterForSatelliteCapabilitiesChanged()"); + + int error = evaluateOemSatelliteRequestAllowed(true); + if (error == SATELLITE_RESULT_SUCCESS) { + mSatelliteCapabilitiesChangedListeners.remove(callback.asBinder()); + } } /** @@ -1821,7 +2096,14 @@ public class SatelliteController extends Handler { * {@code false} otherwise. */ public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { - if (!isMockModemAllowed()) return false; + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setSatelliteServicePackageName: oemEnabledSatelliteFlag is disabled"); + return false; + } + if (!isMockModemAllowed()) { + logd("setSatelliteServicePackageName: mock modem not allowed"); + return false; + } // Cached states need to be cleared whenever switching satellite vendor services. logd("setSatelliteServicePackageName: Resetting cached states"); @@ -1850,6 +2132,10 @@ public class SatelliteController extends Handler { * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. */ public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setSatelliteListeningTimeoutDuration: oemEnabledSatelliteFlag is disabled"); + return false; + } if (mSatelliteSessionController == null) { loge("mSatelliteSessionController is not initialized yet"); return false; @@ -1865,6 +2151,10 @@ public class SatelliteController extends Handler { * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. */ public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setSatelliteDeviceAlignedTimeoutDuration: oemEnabledSatelliteFlag is disabled"); + return false; + } return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis); } @@ -1876,6 +2166,10 @@ public class SatelliteController extends Handler { * {@code false} otherwise. */ public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setSatelliteGatewayServicePackageName: oemEnabledSatelliteFlag is disabled"); + return false; + } if (mSatelliteSessionController == null) { loge("mSatelliteSessionController is not initialized yet"); return false; @@ -1894,10 +2188,61 @@ public class SatelliteController extends Handler { */ public boolean setSatellitePointingUiClassName( @Nullable String packageName, @Nullable String className) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setSatellitePointingUiClassName: oemEnabledSatelliteFlag is disabled"); + return false; + } return mPointingAppController.setSatellitePointingUiClassName(packageName, className); } /** + * This API can be used in only testing to override connectivity status in monitoring emergency + * calls and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer. + * + * @param handoverType The type of handover from emergency call to satellite messaging. Use one + * of the following values to enable the override: + * 0 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS + * 1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 + * To disable the override, use -1 for handoverType. + * @param delaySeconds The event EVENT_DISPLAY_EMERGENCY_MESSAGE will be sent to Dialer + * delaySeconds after the emergency call starts. + * @return {@code true} if the handover type is set successfully, {@code false} otherwise. + */ + public boolean setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds) { + if (!isMockModemAllowed()) { + loge("setEmergencyCallToSatelliteHandoverType: mock modem not allowed"); + return false; + } + if (isHandoverTypeValid(handoverType)) { + mEnforcedEmergencyCallToSatelliteHandoverType = handoverType; + mDelayInSendingEventDisplayEmergencyMessage = delaySeconds > 0 ? delaySeconds : 0; + } else { + mEnforcedEmergencyCallToSatelliteHandoverType = + INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; + mDelayInSendingEventDisplayEmergencyMessage = 0; + } + return true; + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected int getEnforcedEmergencyCallToSatelliteHandoverType() { + return mEnforcedEmergencyCallToSatelliteHandoverType; + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected int getDelayInSendingEventDisplayEmergencyMessage() { + return mDelayInSendingEventDisplayEmergencyMessage; + } + + private boolean isHandoverTypeValid(int handoverType) { + if (handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS + || handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911) { + return true; + } + return false; + } + + /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. * <p> @@ -1910,6 +2255,10 @@ public class SatelliteController extends Handler { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void onSatelliteServiceConnected() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("onSatelliteServiceConnected: oemEnabledSatelliteFlag is disabled"); + return; + } if (mSatelliteModemInterface.isSatelliteServiceSupported()) { synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported == null) { @@ -1932,33 +2281,75 @@ public class SatelliteController extends Handler { } /** - * @return {@code true} is satellite is supported on the device, {@code false} otherwise. + * This function is used by {@link com.android.internal.telephony.ServiceStateTracker} to notify + * {@link SatelliteController} that it has received a request to power off the cellular radio + * modem. {@link SatelliteController} will then power off the satellite modem. */ - public boolean isSatelliteSupported() { - Boolean supported = isSatelliteSupportedInternal(); + public void onCellularRadioPowerOffRequested() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("onCellularRadioPowerOffRequested: oemEnabledSatelliteFlag is disabled"); + return; + } + + mIsRadioOn = false; + requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + false /* enableSatellite */, false /* enableDemoMode */, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("onRadioPowerOffRequested: requestSatelliteEnabled result=" + result); + } + }); + } + + /** + * @return {@code true} if satellite is supported via OEM on the device, + * {@code false} otherwise. + */ + public boolean isSatelliteSupportedViaOem() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("isSatelliteSupported: oemEnabledSatelliteFlag is disabled"); + return false; + } + Boolean supported = isSatelliteSupportedViaOemInternal(); return (supported != null ? supported : false); } /** + * @param subId Subscription ID. * @return The list of satellite PLMNs used for connecting to satellite networks. */ @NonNull - public List<String> getSatellitePlmnList() { - return new ArrayList<>(mSatellitePlmnList); + public List<String> getSatellitePlmnList(int subId) { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("getSatellitePlmnList: carrierEnabledSatelliteFlag is disabled"); + return new ArrayList<>(); + } + synchronized (mSupportedSatelliteServicesLock) { + if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) { + return new ArrayList<>(mSatelliteServicesSupportedByCarriers.get(subId).keySet()); + } else { + return new ArrayList<>(); + } + } } /** * @param subId Subscription ID. - * @param plmn The satellite roaming plmn. + * @param plmn The satellite plmn. * @return The list of services supported by the carrier associated with the {@code subId} for * the satellite network {@code plmn}. */ @NonNull public List<Integer> getSupportedSatelliteServices(int subId, String plmn) { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("getSupportedSatelliteServices: carrierEnabledSatelliteFlag is disabled"); + return new ArrayList<>(); + } synchronized (mSupportedSatelliteServicesLock) { - if (mSupportedSatelliteServices.containsKey(subId)) { + if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) { Map<String, Set<Integer>> supportedServices = - mSupportedSatelliteServices.get(subId); + mSatelliteServicesSupportedByCarriers.get(subId); if (supportedServices != null && supportedServices.containsKey(plmn)) { return new ArrayList<>(supportedServices.get(plmn)); } else { @@ -1966,18 +2357,125 @@ public class SatelliteController extends Handler { + "does not contain key plmn=" + plmn); } } else { - loge("getSupportedSatelliteServices: mSupportedSatelliteServices does contain key" - + " subId=" + subId); + loge("getSupportedSatelliteServices: mSatelliteServicesSupportedByCarriers does " + + "not contain key subId=" + subId); } return new ArrayList<>(); } } /** + * Check whether satellite modem has to attach to a satellite network before sending/receiving + * datagrams. + * + * @return {@code true} if satellite attach is required, {@code false} otherwise. + */ + public boolean isSatelliteAttachRequired() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("isSatelliteAttachRequired: oemEnabledSatelliteFlag is disabled"); + return false; + } + + synchronized (mSatelliteCapabilitiesLock) { + if (mSatelliteCapabilities == null) { + loge("isSatelliteAttachRequired: mSatelliteCapabilities is null"); + return false; + } + if (mSatelliteCapabilities.getSupportedRadioTechnologies().contains( + SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN)) { + return true; + } + return false; + } + } + + /** + * @return {@code true} if satellite is supported via carrier by any subscription on the device, + * {@code false} otherwise. + */ + public boolean isSatelliteSupportedViaCarrier() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("isSatelliteSupportedViaCarrier: carrierEnabledSatelliteFlag is disabled"); + return false; + } + for (Phone phone : PhoneFactory.getPhones()) { + if (isSatelliteSupportedViaCarrier(phone.getSubId())) { + return true; + } + } + return false; + } + + /** + * @return {@code true} if any subscription on the device is connected to satellite, + * {@code false} otherwise. + */ + private boolean isUsingNonTerrestrialNetworkViaCarrier() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("isUsingNonTerrestrialNetwork: carrierEnabledSatelliteFlag is disabled"); + return false; + } + for (Phone phone : PhoneFactory.getPhones()) { + ServiceState serviceState = phone.getServiceState(); + if (serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) { + return true; + } + } + return false; + } + + /** + * @return {@code true} if the device is connected to satellite via any carrier within the + * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT} + * duration, {@code false} otherwise. + */ + public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: carrierEnabledSatelliteFlag" + + " is disabled"); + return false; + } + if (isUsingNonTerrestrialNetworkViaCarrier()) { + return true; + } + for (Phone phone : PhoneFactory.getPhones()) { + if (isSatelliteSupportedViaCarrier(phone.getSubId())) { + synchronized (mSatelliteConnectedLock) { + Boolean isHysteresisTimeExpired = + mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.get( + phone.getSubId()); + if (isHysteresisTimeExpired != null && isHysteresisTimeExpired) { + continue; + } + + Long lastDisconnectedTime = + mLastSatelliteDisconnectedTimesMillis.get(phone.getSubId()); + long satelliteConnectionHysteresisTime = + getSatelliteConnectionHysteresisTimeMillis(phone.getSubId()); + if (lastDisconnectedTime != null + && (getElapsedRealtime() - lastDisconnectedTime) + <= satelliteConnectionHysteresisTime) { + return true; + } else { + mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put( + phone.getSubId(), true); + } + } + } + } + return false; + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected long getElapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + + /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the cached result. */ - private Boolean isSatelliteSupportedInternal() { + private Boolean isSatelliteSupportedViaOemInternal() { synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported != null) { /* We have already successfully queried the satellite modem. */ @@ -2000,7 +2498,7 @@ public class SatelliteController extends Handler { private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, - @SatelliteManager.SatelliteError int result) { + @SatelliteManager.SatelliteResult int result) { logd("handleEventProvisionSatelliteServiceDone: result=" + result + ", subId=" + arg.subId); @@ -2009,11 +2507,11 @@ public class SatelliteController extends Handler { loge("handleEventProvisionSatelliteServiceDone: callback is null for subId=" + arg.subId); mProvisionMetricsStats - .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) + .setResultCode(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE) .setIsProvisionRequest(true) .reportProvisionMetrics(); mControllerMetricsStats.reportProvisionCount( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE); return; } callback.accept(result); @@ -2021,7 +2519,7 @@ public class SatelliteController extends Handler { private void handleEventDeprovisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, - @SatelliteManager.SatelliteError int result) { + @SatelliteManager.SatelliteResult int result) { if (arg == null) { loge("handleEventDeprovisionSatelliteServiceDone: arg is null"); return; @@ -2046,12 +2544,12 @@ public class SatelliteController extends Handler { "handleStartSatelliteTransmissionUpdatesDone"); arg.errorCallback.accept(errorCode); - if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { + if (errorCode != SATELLITE_RESULT_SUCCESS) { mPointingAppController.setStartedSatelliteTransmissionUpdates(false); // We need to remove the callback from our listener list since the caller might not call // stopSatelliteTransmissionUpdates to unregister the callback in case of failure. mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId, - arg.errorCallback, arg.callback, request.phone); + arg.errorCallback, arg.callback); } else { mPointingAppController.setStartedSatelliteTransmissionUpdates(true); } @@ -2108,7 +2606,7 @@ public class SatelliteController extends Handler { * @return true if satellite is provisioned on the given subscription else return false. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected Boolean isSatelliteProvisioned() { + protected Boolean isSatelliteViaOemProvisioned() { synchronized (mIsSatelliteProvisionedLock) { if (mIsSatelliteProvisioned != null) { return mIsSatelliteProvisioned; @@ -2128,10 +2626,7 @@ public class SatelliteController extends Handler { private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; - Phone phone = request.phone; - - if (!argument.enableSatellite && (mSatelliteModemInterface.isSatelliteServiceSupported() - || phone != null)) { + if (!argument.enableSatellite && mSatelliteModemInterface.isSatelliteServiceSupported()) { synchronized (mIsSatelliteEnabledLock) { mWaitingForDisableSatelliteModemResponse = true; mWaitingForSatelliteModemOff = true; @@ -2139,18 +2634,23 @@ public class SatelliteController extends Handler { } Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, - argument.enableDemoMode, onCompleted); - return; - } + mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, + argument.enableDemoMode, onCompleted); + } - if (phone != null) { - phone.setSatellitePower(onCompleted, argument.enableSatellite); - } else { - loge("requestSatelliteEnabled: No phone object"); - argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + private void handleRequestSatelliteAttachRestrictionForCarrierCmd( + SatelliteControllerHandlerRequest request) { + RequestHandleSatelliteAttachRestrictionForCarrierArgument argument = + (RequestHandleSatelliteAttachRestrictionForCarrierArgument) request.argument; + + if (argument.reason == SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER) { + if (!persistSatelliteAttachEnabledForCarrierSetting(argument.subId)) { + argument.callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE); + return; + } } + + evaluateEnablingSatelliteForCarrier(argument.subId, argument.reason, argument.callback); } private void updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported) { @@ -2163,6 +2663,8 @@ public class SatelliteController extends Handler { registerForSatelliteProvisionStateChanged(); registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); + registerForNtnSignalStrengthChanged(); + registerForSatelliteCapabilitiesChanged(); requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, new ResultReceiver(this) { @@ -2208,15 +2710,6 @@ public class SatelliteController extends Handler { this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); mRegisteredForProvisionStateChangedWithSatelliteService.set(true); } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteProvisionStateChanged: phone is null"); - } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { - phone.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithPhone.set(true); - } } } @@ -2227,15 +2720,6 @@ public class SatelliteController extends Handler { this, EVENT_PENDING_DATAGRAMS, null); mRegisteredForPendingDatagramCountWithSatelliteService.set(true); } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForPendingDatagramCount: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { - phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithPhone.set(true); - } } } @@ -2246,15 +2730,35 @@ public class SatelliteController extends Handler { this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { - phone.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithPhone.set(true); + } + } + + private void registerForNtnSignalStrengthChanged() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("registerForNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled"); + return; + } + + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForNtnSignalStrengthChanged.get()) { + mSatelliteModemInterface.registerForNtnSignalStrengthChanged( + this, EVENT_NTN_SIGNAL_STRENGTH_CHANGED, null); + mRegisteredForNtnSignalStrengthChanged.set(true); + } + } + } + + private void registerForSatelliteCapabilitiesChanged() { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("registerForSatelliteCapabilitiesChanged: oemEnabledSatelliteFlag is disabled"); + return; + } + + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForSatelliteCapabilitiesChanged.get()) { + mSatelliteModemInterface.registerForSatelliteCapabilitiesChanged( + this, EVENT_SATELLITE_CAPABILITIES_CHANGED, null); + mRegisteredForSatelliteCapabilitiesChanged.set(true); } } } @@ -2266,16 +2770,16 @@ public class SatelliteController extends Handler { mIsSatelliteProvisioned = provisioned; } - List<ISatelliteProvisionStateCallback> toBeRemoved = new ArrayList<>(); + List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>(); mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { try { listener.onSatelliteProvisionStateChanged(provisioned); } catch (RemoteException e) { logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); - toBeRemoved.add(listener); + deadCallersList.add(listener); } }); - toBeRemoved.forEach(listener -> { + deadCallersList.forEach(listener -> { mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); }); } @@ -2290,8 +2794,8 @@ public class SatelliteController extends Handler { || ((mIsSatelliteEnabled == null || isSatelliteEnabled()) && !mWaitingForDisableSatelliteModemResponse)) { int error = (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF) - ? SatelliteManager.SATELLITE_ERROR_NONE - : SatelliteManager.SATELLITE_INVALID_MODEM_STATE; + ? SATELLITE_RESULT_SUCCESS + : SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE; Consumer<Integer> callback = null; synchronized (mSatelliteEnabledRequestLock) { if (mSatelliteEnabledRequest != null) { @@ -2307,8 +2811,63 @@ public class SatelliteController extends Handler { } mWaitingForSatelliteModemOff = false; } + } else { + if (mSatelliteSessionController != null) { + mSatelliteSessionController.onSatelliteModemStateChanged(state); + } else { + loge("handleEventSatelliteModemStateChanged: mSatelliteSessionController is null"); + } + } + } + + private void handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) { + logd("handleEventNtnSignalStrengthChanged: ntnSignalStrength=" + ntnSignalStrength); + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("handleEventNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled"); + return; } - mDatagramController.onSatelliteModemStateChanged(state); + + synchronized (mNtnSignalsStrengthLock) { + mNtnSignalStrength = ntnSignalStrength; + } + + List<INtnSignalStrengthCallback> deadCallersList = new ArrayList<>(); + mNtnSignalStrengthChangedListeners.values().forEach(listener -> { + try { + listener.onNtnSignalStrengthChanged(ntnSignalStrength); + } catch (RemoteException e) { + logd("handleEventNtnSignalStrengthChanged RemoteException: " + e); + deadCallersList.add(listener); + } + }); + deadCallersList.forEach(listener -> { + mNtnSignalStrengthChangedListeners.remove(listener.asBinder()); + }); + } + + private void handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) { + logd("handleEventSatelliteCapabilitiesChanged()"); + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("handleEventSatelliteCapabilitiesChanged: oemEnabledSatelliteFlag is disabled"); + return; + } + + synchronized (mSatelliteCapabilitiesLock) { + mSatelliteCapabilities = capabilities; + } + + List<ISatelliteCapabilitiesCallback> deadCallersList = new ArrayList<>(); + mSatelliteCapabilitiesChangedListeners.values().forEach(listener -> { + try { + listener.onSatelliteCapabilitiesChanged(capabilities); + } catch (RemoteException e) { + logd("handleEventSatelliteCapabilitiesChanged RemoteException: " + e); + deadCallersList.add(listener); + } + }); + deadCallersList.forEach(listener -> { + mSatelliteCapabilitiesChangedListeners.remove(listener.asBinder()); + }); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @@ -2343,7 +2902,7 @@ public class SatelliteController extends Handler { synchronized (mIsSatelliteEnabledLock) { mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite; } - mSatelliteEnabledRequest.callback.accept(SatelliteManager.SATELLITE_ERROR_NONE); + mSatelliteEnabledRequest.callback.accept(SATELLITE_RESULT_SUCCESS); updateSatelliteEnabledState( mSatelliteEnabledRequest.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); @@ -2362,7 +2921,7 @@ public class SatelliteController extends Handler { } private void moveSatelliteToOffStateAndCleanUpResources( - @SatelliteManager.SatelliteError int error, @Nullable Consumer<Integer> callback) { + @SatelliteManager.SatelliteResult int error, @Nullable Consumer<Integer> callback) { logd("moveSatelliteToOffStateAndCleanUpResources"); synchronized (mIsSatelliteEnabledLock) { resetSatelliteEnabledRequest(); @@ -2384,10 +2943,43 @@ public class SatelliteController extends Handler { return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); } + private void configureSatellitePlmnForCarrier(int subId) { + logd("configureSatellitePlmnForCarrier"); + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("configureSatellitePlmnForCarrier: carrierEnabledSatelliteFlag is disabled"); + return; + } + synchronized (mSupportedSatelliteServicesLock) { + List<String> carrierPlmnList; + if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) { + carrierPlmnList = + mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList(); + } else { + carrierPlmnList = new ArrayList<>(); + } + int slotId = SubscriptionManager.getSlotIndex(subId); + mSatelliteModemInterface.setSatellitePlmn(slotId, carrierPlmnList, + SatelliteServiceUtils.mergeStrLists( + carrierPlmnList, mSatellitePlmnListFromOverlayConfig), + obtainMessage(EVENT_SET_SATELLITE_PLMN_INFO_DONE)); + } + } + + private void handleSetSatellitePlmnInfoDoneEvent(Message msg) { + AsyncResult ar = (AsyncResult) msg.obj; + SatelliteServiceUtils.getSatelliteError(ar, "handleSetSatellitePlmnInfoCmd"); + } + private void updateSupportedSatelliteServicesForActiveSubscriptions() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("updateSupportedSatelliteServicesForActiveSubscriptions: " + + "carrierEnabledSatelliteFlag is disabled"); + return; + } + synchronized (mSupportedSatelliteServicesLock) { - mSupportedSatelliteServices.clear(); - int[] activeSubIds = SubscriptionManagerService.getInstance().getActiveSubIdList(true); + mSatelliteServicesSupportedByCarriers.clear(); + int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true); if (activeSubIds != null) { for (int subId : activeSubIds) { updateSupportedSatelliteServices(subId); @@ -2400,21 +2992,22 @@ public class SatelliteController extends Handler { } private void updateSupportedSatelliteServices(int subId) { - Map<String, Set<Integer>> carrierSupportedSatelliteServicesPerPlmn = - readSupportedSatelliteServicesFromCarrierConfig(subId); synchronized (mSupportedSatelliteServicesLock) { - mSupportedSatelliteServices.put(subId, - SatelliteServiceUtils.mergeSupportedSatelliteServices( - mSatelliteServicesSupportedByProviders, - carrierSupportedSatelliteServicesPerPlmn)); + mSatelliteServicesSupportedByCarriers.put( + subId, readSupportedSatelliteServicesFromCarrierConfig(subId)); } } @NonNull - private Map<String, Set<Integer>> readSupportedSatelliteServicesFromOverlayConfig() { - String[] supportedServices = readStringArrayFromOverlayConfig( - R.array.config_satellite_services_supported_by_providers); - return SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServices); + private List<String> readSatellitePlmnsFromOverlayConfig() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + logd("readSatellitePlmnsFromOverlayConfig: carrierEnabledSatelliteFlag is disabled"); + return new ArrayList<>(); + } + + String[] devicePlmns = readStringArrayFromOverlayConfig( + R.array.config_satellite_providers); + return Arrays.stream(devicePlmns).toList(); } @NonNull @@ -2426,15 +3019,16 @@ public class SatelliteController extends Handler { mCarrierConfigArray.put(subId, config); } return SatelliteServiceUtils.parseSupportedSatelliteServices( - config.getPersistableBundle(CarrierConfigManager - .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE)); + config.getPersistableBundle( + KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE)); } } @NonNull private PersistableBundle getConfigForSubId(int subId) { PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId, - CarrierConfigManager - .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE); + KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, + KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT); if (config == null || config.isEmpty()) { config = CarrierConfigManager.getDefaultConfig(); } @@ -2452,14 +3046,40 @@ public class SatelliteController extends Handler { updateCarrierConfig(subId); updateSupportedSatelliteServicesForActiveSubscriptions(); + configureSatellitePlmnForCarrier(subId); + + synchronized (mIsSatelliteEnabledLock) { + mSatelliteAttachRestrictionForCarrierArray.clear(); + mIsSatelliteAttachEnabledForCarrierArrayPerSub.clear(); + } + + setSatelliteAttachEnabledForCarrierOnSimLoaded(subId); } - private void updateCarrierConfig(int subId) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected void updateCarrierConfig(int subId) { synchronized (mCarrierConfigArrayLock) { mCarrierConfigArray.put(subId, getConfigForSubId(subId)); } } + /** + * When a SIM is loaded, we need to check if users has enabled satellite attach for the carrier + * associated with the SIM, and evaluate if satellite should be enabled for the carrier. + * + * @param subId Subscription ID. + */ + private void setSatelliteAttachEnabledForCarrierOnSimLoaded(int subId) { + synchronized (mIsSatelliteEnabledLock) { + if (isSatelliteAttachEnabledForCarrierByUser(subId) + && !mIsSatelliteAttachEnabledForCarrierArrayPerSub.getOrDefault(subId, + false)) { + evaluateEnablingSatelliteForCarrier(subId, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, null); + } + } + } + @NonNull private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) { String[] strArray = null; @@ -2474,6 +3094,317 @@ public class SatelliteController extends Handler { return strArray; } + private boolean isSatelliteSupportedViaCarrier(int subId) { + return getConfigForSubId(subId) + .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL); + } + + /** + * Check if satellite attach is enabled by user for the carrier associated with the + * {@code subId}. + * + * @param subId Subscription ID. + * + * @return Returns {@code true} if satellite attach for carrier is enabled by user, + * {@code false} otherwise. + */ + private boolean isSatelliteAttachEnabledForCarrierByUser(int subId) { + synchronized (mIsSatelliteEnabledLock) { + Set<Integer> cachedRestrictionSet = + mSatelliteAttachRestrictionForCarrierArray.get(subId); + if (cachedRestrictionSet != null) { + return !cachedRestrictionSet.contains( + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER); + } else { + logd("isSatelliteAttachEnabledForCarrierByUser() no correspondent cache, " + + "load from persist storage"); + try { + String enabled = + mSubscriptionManagerService.getSubscriptionProperty(subId, + SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + mContext.getOpPackageName(), mContext.getAttributionTag()); + + if (enabled == null) { + loge("isSatelliteAttachEnabledForCarrierByUser: invalid subId, subId=" + + subId); + return false; + } + + if (enabled.isEmpty()) { + loge("isSatelliteAttachEnabledForCarrierByUser: no data for subId(" + subId + + ")"); + return false; + } + + synchronized (mIsSatelliteEnabledLock) { + boolean result = enabled.equals("1"); + if (!result) { + mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>()); + mSatelliteAttachRestrictionForCarrierArray.get(subId).add( + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER); + } + return result; + } + } catch (IllegalArgumentException | SecurityException ex) { + loge("isSatelliteAttachEnabledForCarrierByUser: ex=" + ex); + return false; + } + } + } + } + + /** + * Check whether there is any reason to restrict satellite communication for the carrier + * associated with the {@code subId}. + * + * @param subId Subscription ID + * @return {@code true} when there is at least on reason, {@code false} otherwise. + */ + private boolean hasReasonToRestrictSatelliteCommunicationForCarrier(int subId) { + synchronized (mIsSatelliteEnabledLock) { + return !mSatelliteAttachRestrictionForCarrierArray + .getOrDefault(subId, Collections.emptySet()).isEmpty(); + } + } + + /** + * Save user setting for enabling satellite attach for the carrier associated with the + * {@code subId} to persistent storage. + * + * @param subId Subscription ID. + * + * @return {@code true} if persist successful, {@code false} otherwise. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected boolean persistSatelliteAttachEnabledForCarrierSetting(int subId) { + logd("persistSatelliteAttachEnabledForCarrierSetting"); + if (!isValidSubscriptionId(subId)) { + loge("persistSatelliteAttachEnabledForCarrierSetting: subId is not valid," + + " subId=" + subId); + return false; + } + + synchronized (mIsSatelliteEnabledLock) { + try { + mSubscriptionManagerService.setSubscriptionProperty(subId, + SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + mSatelliteAttachRestrictionForCarrierArray.get(subId) + .contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER) + ? "0" : "1"); + } catch (IllegalArgumentException | SecurityException ex) { + loge("persistSatelliteAttachEnabledForCarrierSetting, ex=" + ex); + return false; + } + } + return true; + } + + /** + * Evaluate whether satellite attach for carrier should be restricted. + * + * @param subId Subscription Id to evaluate for. + * @return {@code true} satellite attach is restricted, {@code false} otherwise. + */ + private boolean isSatelliteRestrictedForCarrier(int subId) { + return !isSatelliteAttachEnabledForCarrierByUser(subId) + || hasReasonToRestrictSatelliteCommunicationForCarrier(subId); + } + + /** + * Check whether satellite is enabled for carrier at modem. + * + * @param subId Subscription ID to check for. + * @return {@code true} if satellite modem is enabled, {@code false} otherwise. + */ + private boolean isSatelliteEnabledForCarrierAtModem(int subId) { + synchronized (mIsSatelliteEnabledLock) { + return mIsSatelliteAttachEnabledForCarrierArrayPerSub.getOrDefault(subId, false); + } + } + + /** + * Evaluate whether satellite modem for carrier should be enabled or not. + * <p> + * Satellite will be enabled only when the following conditions are met: + * <ul> + * <li>Users want to enable it.</li> + * <li>There is no satellite communication restriction, which is added by + * {@link #addSatelliteAttachRestrictionForCarrier(int, int, IIntegerConsumer)}</li> + * <li>The carrier config {@link + * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to + * {@code true}.</li> + * </ul> + * + * @param subId Subscription Id for evaluate for. + * @param callback The callback for getting the result of enabling satellite. + */ + private void evaluateEnablingSatelliteForCarrier(int subId, int reason, + @Nullable Consumer<Integer> callback) { + if (callback == null) { + callback = errorCode -> logd("evaluateEnablingSatelliteForCarrier: " + + "SetSatelliteAttachEnableForCarrier error code =" + errorCode); + } + + if (!isSatelliteSupportedViaCarrier(subId)) { + logd("Satellite for carrier is not supported. Only user setting is stored"); + callback.accept(SATELLITE_RESULT_SUCCESS); + return; + } + + /* Request to enable or disable the satellite in the cellular modem only when the desired + state and the current state are different. */ + boolean isSatelliteExpectedToBeEnabled = !isSatelliteRestrictedForCarrier(subId); + if (isSatelliteExpectedToBeEnabled != isSatelliteEnabledForCarrierAtModem(subId)) { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + int simSlot = SubscriptionManager.getSlotIndex(subId); + RequestHandleSatelliteAttachRestrictionForCarrierArgument argument = + new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, + reason, callback); + SatelliteControllerHandlerRequest request = + new SatelliteControllerHandlerRequest(argument, + SatelliteServiceUtils.getPhone(subId)); + Message onCompleted = obtainMessage( + EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE, request); + mSatelliteModemInterface.requestSetSatelliteEnabledForCarrier(simSlot, + isSatelliteExpectedToBeEnabled, onCompleted); + } else { + callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE); + } + } else { + callback.accept(SATELLITE_RESULT_SUCCESS); + } + } + + @SatelliteManager.SatelliteResult private int evaluateOemSatelliteRequestAllowed( + boolean isProvisionRequired) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("oemEnabledSatelliteFlag is disabled"); + return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { + return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + } + + Boolean satelliteSupported = isSatelliteSupportedViaOemInternal(); + if (satelliteSupported == null) { + return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; + } + if (!satelliteSupported) { + return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; + } + + if (isProvisionRequired) { + Boolean satelliteProvisioned = isSatelliteViaOemProvisioned(); + if (satelliteProvisioned == null) { + return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; + } + if (!satelliteProvisioned) { + return SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED; + } + } + + return SATELLITE_RESULT_SUCCESS; + } + + /** + * Returns the non-terrestrial network radio technology that the satellite modem currently + * supports. If multiple technologies are available, returns the first supported technology. + */ + @VisibleForTesting + protected @SatelliteManager.NTRadioTechnology int getSupportedNtnRadioTechnology() { + synchronized (mSatelliteCapabilitiesLock) { + if (mSatelliteCapabilities != null) { + return mSatelliteCapabilities.getSupportedRadioTechnologies() + .stream().findFirst().orElse(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN); + } + return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN; + } + } + + private void sendErrorAndReportSessionMetrics(@SatelliteManager.SatelliteResult int error, + Consumer<Integer> result) { + result.accept(error); + SessionMetricsStats.getInstance() + .setInitializationResult(error) + .setRadioTechnology(getSupportedNtnRadioTechnology()) + .reportSessionMetrics(); + } + + private void registerForServiceStateChanged() { + if (!mFeatureFlags.carrierEnabledSatelliteFlag()) { + return; + } + for (Phone phone : PhoneFactory.getPhones()) { + phone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); + } + } + + private void handleEventServiceStateChanged() { + handleServiceStateForSatelliteConnectionViaCarrier(); + } + + private void handleServiceStateForSatelliteConnectionViaCarrier() { + for (Phone phone : PhoneFactory.getPhones()) { + ServiceState serviceState = phone.getServiceState(); + if (serviceState != null) { + synchronized (mSatelliteConnectedLock) { + if (serviceState.isUsingNonTerrestrialNetwork()) { + mWasSatelliteConnectedViaCarrier.put(phone.getSubId(), true); + mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put( + phone.getSubId(), false); + } else { + Boolean connected = mWasSatelliteConnectedViaCarrier.get(phone.getSubId()); + if (connected != null && connected) { + // The device just got disconnected from a satellite network. + mLastSatelliteDisconnectedTimesMillis.put( + phone.getSubId(), getElapsedRealtime()); + mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put( + phone.getSubId(), false); + } + mWasSatelliteConnectedViaCarrier.put(phone.getSubId(), false); + } + } + } + } + } + + private long getSatelliteConnectionHysteresisTimeMillis(int subId) { + synchronized (mCarrierConfigArrayLock) { + PersistableBundle config = mCarrierConfigArray.get(subId); + if (config == null) { + config = getConfigForSubId(subId); + mCarrierConfigArray.put(subId, config); + } + return (config.getInt( + KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L); + } + } + + /** + * This API can be used by only CTS to override the cached value for the device overlay config + * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether + * outgoing satellite datagrams should be sent to modem in demo mode. + * + * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to + * satellite modem or not. + * + * @return {@code true} if the operation is successful, {@code false} otherwise. + */ + public boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + logd("setShouldSendDatagramToModemInDemoMode: oemEnabledSatelliteFlag is disabled"); + return false; + } + + if (!isMockModemAllowed()) { + logd("setShouldSendDatagramToModemInDemoMode: mock modem not allowed."); + return false; + } + + mDatagramController.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode); + return true; + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index ebf7780a49..03481c6f6c 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -30,11 +30,15 @@ import android.os.Looper; import android.os.Message; import android.os.RegistrantList; import android.os.RemoteException; +import android.telephony.IBooleanConsumer; +import android.telephony.IIntegerConsumer; import android.telephony.Rlog; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.SatelliteManager.SatelliteException; +import android.telephony.satellite.stub.INtnSignalStrengthConsumer; import android.telephony.satellite.stub.ISatellite; import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; import android.telephony.satellite.stub.ISatelliteListener; @@ -45,10 +49,9 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ExponentialBackoff; -import com.android.internal.telephony.IBooleanConsumer; -import com.android.internal.telephony.IIntegerConsumer; import java.util.Arrays; +import java.util.List; /** * Satellite modem interface to manage connections with the satellite service and HAL interface. @@ -86,6 +89,10 @@ public class SatelliteModemInterface { @NonNull private final RegistrantList mPendingDatagramsRegistrants = new RegistrantList(); @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants = new RegistrantList(); + @NonNull private final RegistrantList mNtnSignalStrengthChangedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mSatelliteCapabilitiesChangedRegistrants = + new RegistrantList(); @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() { @Override @@ -96,12 +103,14 @@ public class SatelliteModemInterface { @Override public void onSatelliteDatagramReceived( android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount) { + logd("onSatelliteDatagramReceived: pendingCount=" + pendingCount); mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>( SatelliteServiceUtils.fromSatelliteDatagram(datagram), pendingCount)); } @Override public void onPendingDatagrams() { + logd("onPendingDatagrams"); mPendingDatagramsRegistrants.notifyResult(null); } @@ -135,6 +144,20 @@ public class SatelliteModemInterface { } mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState); } + + @Override + public void onNtnSignalStrengthChanged( + android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) { + mNtnSignalStrengthChangedRegistrants.notifyResult( + SatelliteServiceUtils.fromNtnSignalStrength(ntnSignalStrength)); + } + + @Override + public void onSatelliteCapabilitiesChanged( + android.telephony.satellite.stub.SatelliteCapabilities satelliteCapabilities) { + mSatelliteCapabilitiesChangedRegistrants.notifyResult( + SatelliteServiceUtils.fromSatelliteCapabilities(satelliteCapabilities)); + } }; /** @@ -440,6 +463,48 @@ public class SatelliteModemInterface { } /** + * Registers for non-terrestrial signal strength level changed. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForNtnSignalStrengthChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mNtnSignalStrengthChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for non-terrestrial signal strength level changed. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForNtnSignalStrengthChanged(@NonNull Handler h) { + mNtnSignalStrengthChangedRegistrants.remove(h); + } + + /** + * Registers for satellite capabilities changed. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteCapabilitiesChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatelliteCapabilitiesChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for satellite capabilities changed. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteCapabilitiesChanged(@NonNull Handler h) { + mSatelliteCapabilitiesChangedRegistrants.remove(h); + } + + /** * Request to enable or disable the satellite service listening mode. * Listening mode allows the satellite service to listen for incoming pages. * @@ -469,14 +534,14 @@ public class SatelliteModemInterface { loge("requestSatelliteListeningEnabled: RemoteException " + e); if (message != null) { sendMessageWithResult( - message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + message, null, SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } } else { loge("requestSatelliteListeningEnabled: Satellite service is unavailable."); if (message != null) { sendMessageWithResult(message, null, - SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } } @@ -508,14 +573,14 @@ public class SatelliteModemInterface { loge("enableCellularModemWhileSatelliteModeIsOn: RemoteException " + e); if (message != null) { sendMessageWithResult( - message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + message, null, SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } } else { loge("enableCellularModemWhileSatelliteModeIsOn: Satellite service is unavailable."); if (message != null) { sendMessageWithResult(message, null, - SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } } @@ -544,11 +609,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("setSatelliteEnabled: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("setSatelliteEnabled: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -576,16 +643,18 @@ public class SatelliteModemInterface { int[] enabled = new int[] {result ? 1 : 0}; logd("requestIsSatelliteEnabled: " + Arrays.toString(enabled)); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, enabled, SatelliteManager.SATELLITE_ERROR_NONE)); + message, enabled, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestIsSatelliteEnabled: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestIsSatelliteEnabled: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -610,17 +679,18 @@ public class SatelliteModemInterface { public void accept(boolean result) { logd("requestIsSatelliteSupported: " + result); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, result, SatelliteManager.SATELLITE_ERROR_NONE)); + message, result, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestIsSatelliteSupported: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestIsSatelliteSupported: Satellite service is unavailable."); sendMessageWithResult( - message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + message, null, SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -648,16 +718,18 @@ public class SatelliteModemInterface { SatelliteServiceUtils.fromSatelliteCapabilities(result); logd("requestSatelliteCapabilities: " + capabilities); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, capabilities, SatelliteManager.SATELLITE_ERROR_NONE)); + message, capabilities, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestSatelliteCapabilities: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestSatelliteCapabilities: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -682,11 +754,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("startSendingSatellitePointingInfo: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("startSendingSatellitePointingInfo: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -710,11 +784,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("stopSendingSatellitePointingInfo: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("stopSendingSatellitePointingInfo: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -744,11 +820,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("provisionSatelliteService: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("provisionSatelliteService: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -774,11 +852,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("deprovisionSatelliteService: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("deprovisionSatelliteService: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -806,16 +886,18 @@ public class SatelliteModemInterface { int[] provisioned = new int[] {result ? 1 : 0}; logd("requestIsSatelliteProvisioned: " + Arrays.toString(provisioned)); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, provisioned, SatelliteManager.SATELLITE_ERROR_NONE)); + message, provisioned, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestIsSatelliteProvisioned: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestIsSatelliteProvisioned: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -840,11 +922,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("pollPendingSatelliteDatagrams: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("pollPendingSatelliteDatagrams: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -874,11 +958,13 @@ public class SatelliteModemInterface { }); } catch (RemoteException e) { loge("sendSatelliteDatagram: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("sendSatelliteDatagram: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -907,16 +993,18 @@ public class SatelliteModemInterface { int modemState = SatelliteServiceUtils.fromSatelliteModemState(result); logd("requestSatelliteModemState: " + modemState); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, modemState, SatelliteManager.SATELLITE_ERROR_NONE)); + message, modemState, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestSatelliteModemState: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestSatelliteModemState: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -944,18 +1032,21 @@ public class SatelliteModemInterface { logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + result); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, result, SatelliteManager.SATELLITE_ERROR_NONE)); + message, result, + SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + "Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -987,16 +1078,239 @@ public class SatelliteModemInterface { logd("requestTimeForNextSatelliteVisibility: " + Arrays.toString(time)); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, time, SatelliteManager.SATELLITE_ERROR_NONE)); + message, time, SatelliteManager.SATELLITE_RESULT_SUCCESS)); } }); } catch (RemoteException e) { loge("requestTimeForNextSatelliteVisibility: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } } else { loge("requestTimeForNextSatelliteVisibility: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + } + } + + /** + * Set the non-terrestrial PLMN with lower priority than terrestrial networks. + * MCC/MNC broadcast by the non-terrestrial networks will not be included in OPLMNwACT file + * on SIM profile. + * Acquisition of satellite based system is deemed lower priority to terrestrial networks. + * Even so, UE shall make all attempts to acquire terrestrial service prior to camping on + * satellite LTE service. + * + * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use + * this information to determine the relevant carrier. + * @param carrierPlmnList The list of roaming PLMN used for connecting to satellite networks + * supported by user subscription. + * @param allSatellitePlmnList Modem should use the allSatellitePlmnList to identify satellite + * PLMNs that are not supported by the carrier and make sure not to + * attach to them. + * @param message The result receiver that returns whether the modem has + * successfully set the satellite PLMN + */ + public void setSatellitePlmn(@NonNull int simSlot, @NonNull List<String> carrierPlmnList, + @NonNull List<String> allSatellitePlmnList, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.setSatellitePlmn(simSlot, carrierPlmnList, allSatellitePlmnList, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("setSatellitePlmn: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("setSatellitePlmn: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("setSatellitePlmn: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + } + } + + /** + * Enable or disable satellite in the cellular modem associated with a carrier. + * Refer setSatellitePlmn for the details of satellite PLMN scanning process. + * + * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use + * this information to determine the relevant carrier. + * @param enableSatellite True to enable the satellite modem and false to disable. + * @param message The Message to send to result of the operation to. + */ + public void requestSetSatelliteEnabledForCarrier(@NonNull int simSlot, + @NonNull boolean enableSatellite, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.setSatelliteEnabledForCarrier(simSlot, enableSatellite, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("requestSetSatelliteEnabledForCarrier: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("requestSetSatelliteEnabledForCarrier: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("requestSetSatelliteEnabledForCarrier: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Check whether satellite is enabled in the cellular modem associated with a carrier. + * + * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use + * this information to determine the relevant carrier. + * @param message The Message to send to result of the operation to. + */ + public void requestIsSatelliteEnabledForCarrier(@NonNull int simSlot, + @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestIsSatelliteEnabledForCarrier(simSlot, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("requestIsSatelliteEnabledForCarrier: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IBooleanConsumer.Stub() { + @Override + public void accept(boolean result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] enabled = new int[] {result ? 1 : 0}; + logd("requestIsSatelliteEnabledForCarrier: " + + Arrays.toString(enabled)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, enabled, + SatelliteManager.SATELLITE_RESULT_SUCCESS)); + } + }); + } catch (RemoteException e) { + loge("requestIsSatelliteEnabledForCarrier: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("requestIsSatelliteEnabledForCarrier: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + } + } + + /** + * Request to get the signal strength of the satellite connection. + * + * @param message The Message to send to result of the operation to. + */ + public void requestNtnSignalStrength(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestSignalStrength( + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("requestNtnSignalStrength: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new INtnSignalStrengthConsumer.Stub() { + @Override + public void accept(NtnSignalStrength result) { + logd("requestNtnSignalStrength: " + result); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, result, + SatelliteManager.SATELLITE_RESULT_SUCCESS)); + } + }); + } catch (RemoteException e) { + loge("requestNtnSignalStrength: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("requestNtnSignalStrength: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + } + } + + /** + * The satellite service should report the NTN signal strength via + * ISatelliteListener#onNtnSignalStrengthChanged when the NTN signal strength changes. + * + * @param message The Message to send to result of the operation to. + */ + public void startSendingNtnSignalStrength(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.startSendingNtnSignalStrength(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("startSendingNtnSignalStrength: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("startSendingNtnSignalStrength: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("startSendingNtnSignalStrength: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + } + } + + /** + * The satellite service should stop reporting NTN signal strength to the framework. + * + * @param message The Message to send to result of the operation to. + */ + public void stopSendingNtnSignalStrength(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.stopSendingNtnSignalStrength(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("stopSendingNtnSignalStrength: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("stopSendingNtnSignalStrength: RemoteException " + e); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); + } + } else { + loge("stopSendingNtnSignalStrength: Satellite service is unavailable."); + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE); } } @@ -1036,8 +1350,8 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = error == SatelliteManager.SATELLITE_ERROR_NONE + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = error == SatelliteManager.SATELLITE_RESULT_SUCCESS ? null : new SatelliteException(error); AsyncResult.forMessage(message, result, exception); message.sendToTarget(); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index 25657b3d7c..f40880b55a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -16,36 +16,55 @@ package com.android.internal.telephony.satellite; +import static android.telephony.ServiceState.STATE_EMERGENCY_ONLY; +import static android.telephony.ServiceState.STATE_IN_SERVICE; +import static android.telephony.ServiceState.STATE_OUT_OF_SERVICE; +import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; +import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED; -import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; + +import static com.android.internal.telephony.satellite.SatelliteController.INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; import android.annotation.NonNull; -import android.os.AsyncResult; +import android.annotation.Nullable; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ResultReceiver; +import android.os.SystemProperties; import android.provider.DeviceConfig; -import android.telecom.Call; import android.telecom.Connection; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.text.TextUtils; import android.util.Pair; +import android.util.SparseArray; import com.android.ims.ImsException; import com.android.ims.ImsManager; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SmsApplication; import com.android.internal.telephony.metrics.SatelliteStats; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; /** @@ -56,74 +75,48 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class SatelliteSOSMessageRecommender extends Handler { private static final String TAG = "SatelliteSOSMessageRecommender"; - - /** - * Device config for the timeout duration in milliseconds to determine whether to recommend - * Dialer to show the SOS button to users. - * <p> - * The timer is started when there is an ongoing emergency call, and the IMS is not registered, - * and cellular service is not available. When the timer expires, SatelliteSOSMessageRecommender - * will send the event EVENT_DISPLAY_SOS_MESSAGE to Dialer, which will then prompt user to - * switch to using satellite SOS messaging. - */ - public static final String EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = - "emergency_call_to_sos_msg_hysteresis_timeout_millis"; - /** - * The default value of {@link #EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS} when it is - * not provided in the device config. - */ - public static final long DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 20000; - + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; private static final int EVENT_EMERGENCY_CALL_STARTED = 1; - protected static final int EVENT_CELLULAR_SERVICE_STATE_CHANGED = 2; - private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = 3; - protected static final int EVENT_TIME_OUT = 4; - private static final int EVENT_SATELLITE_PROVISIONED_STATE_CHANGED = 5; - private static final int EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED = 6; + protected static final int EVENT_SERVICE_STATE_CHANGED = 2; + protected static final int EVENT_TIME_OUT = 3; + private static final int EVENT_SATELLITE_PROVISIONED_STATE_CHANGED = 4; + private static final int EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED = 5; + private static final int CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY = 6; + @NonNull private final Context mContext; @NonNull private final SatelliteController mSatelliteController; private ImsManager mImsManager; private Connection mEmergencyConnection = null; - /* The phone used for emergency call */ - private Phone mPhone = null; private final ISatelliteProvisionStateCallback mISatelliteProvisionStateCallback; - @ServiceState.RegState - private AtomicInteger mCellularServiceState = new AtomicInteger(); - private AtomicBoolean mIsImsRegistered = new AtomicBoolean(); + /** Key: Phone ID; Value: IMS RegistrationCallback */ + private SparseArray<RegistrationManager.RegistrationCallback> + mImsRegistrationCallbacks = new SparseArray<>(); private AtomicBoolean mIsSatelliteAllowedInCurrentLocation = new AtomicBoolean(); private final ResultReceiver mReceiverForRequestIsSatelliteAllowedForCurrentLocation; private final long mTimeoutMillis; + private final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = + new AtomicBoolean(false); protected int mCountOfTimerStarted = 0; - private RegistrationManager.RegistrationCallback mImsRegistrationCallback = - new RegistrationManager.RegistrationCallback() { - @Override - public void onRegistered(ImsRegistrationAttributes attributes) { - sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, true)); - } - - @Override - public void onUnregistered(ImsReasonInfo info) { - sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, false)); - } - }; - /** * Create an instance of SatelliteSOSMessageRecommender. * + * @param context The Context for the SatelliteSOSMessageRecommender. * @param looper The looper used with the handler of this class. */ - public SatelliteSOSMessageRecommender(@NonNull Looper looper) { - this(looper, SatelliteController.getInstance(), null, - getEmergencyCallToSosMsgHysteresisTimeoutMillis()); + public SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper) { + this(context, looper, SatelliteController.getInstance(), null, + getEmergencyCallWaitForConnectionTimeoutMillis(context)); } /** * Create an instance of SatelliteSOSMessageRecommender. This constructor should be used in * only unit tests. * + * @param context The Context for the SatelliteSOSMessageRecommender. * @param looper The looper used with the handler of this class. * @param satelliteController The SatelliteController singleton instance. * @param imsManager The ImsManager instance associated with the phone, which is used for making @@ -131,10 +124,11 @@ public class SatelliteSOSMessageRecommender extends Handler { * @param timeoutMillis The timeout duration of the timer. */ @VisibleForTesting - protected SatelliteSOSMessageRecommender(@NonNull Looper looper, + protected SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper, @NonNull SatelliteController satelliteController, ImsManager imsManager, long timeoutMillis) { super(looper); + mContext = context; mSatelliteController = satelliteController; mImsManager = imsManager; mTimeoutMillis = timeoutMillis; @@ -148,7 +142,7 @@ public class SatelliteSOSMessageRecommender extends Handler { mReceiverForRequestIsSatelliteAllowedForCurrentLocation = new ResultReceiver(this) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { boolean isSatelliteCommunicationAllowed = resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED); @@ -176,7 +170,7 @@ public class SatelliteSOSMessageRecommender extends Handler { public void handleMessage(@NonNull Message msg) { switch (msg.what) { case EVENT_EMERGENCY_CALL_STARTED: - handleEmergencyCallStartedEvent((Pair<Connection, Phone>) msg.obj); + handleEmergencyCallStartedEvent((Connection) msg.obj); break; case EVENT_TIME_OUT: handleTimeoutEvent(); @@ -187,12 +181,11 @@ public class SatelliteSOSMessageRecommender extends Handler { case EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED: handleEmergencyCallConnectionStateChangedEvent((Pair<String, Integer>) msg.obj); break; - case EVENT_IMS_REGISTRATION_STATE_CHANGED: - handleImsRegistrationStateChangedEvent((boolean) msg.obj); + case EVENT_SERVICE_STATE_CHANGED: + handleStateChangedEventForHysteresisTimer(); break; - case EVENT_CELLULAR_SERVICE_STATE_CHANGED: - AsyncResult ar = (AsyncResult) msg.obj; - handleCellularServiceStateChangedEvent((ServiceState) ar.result); + case CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY: + handleCmdSendEventDisplayEmergencyMessageForcefully((Connection) msg.obj); break; default: logd("handleMessage: unexpected message code: " + msg.what); @@ -205,15 +198,23 @@ public class SatelliteSOSMessageRecommender extends Handler { * * @param connection The connection created by TelephonyConnectionService for the emergency * call. - * @param phone The phone used for the emergency call. */ - public void onEmergencyCallStarted(@NonNull Connection connection, @NonNull Phone phone) { - if (!mSatelliteController.isSatelliteSupported()) { + public void onEmergencyCallStarted(@NonNull Connection connection) { + if (!mSatelliteController.isSatelliteSupportedViaOem() + && !mSatelliteController.isSatelliteSupportedViaCarrier()) { logd("onEmergencyCallStarted: satellite is not supported"); return; } - Pair<Connection, Phone> argument = new Pair<>(connection, phone); - sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, argument)); + + /** + * Right now, assume that the device is connected to satellite via carrier within hysteresis + * time. However, this might not be correct when the monitoring timer expires. Thus, we + * should do this check now so that we have higher chance of sending the event + * EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer. + */ + mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set( + mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, connection)); } /** @@ -225,25 +226,32 @@ public class SatelliteSOSMessageRecommender extends Handler { */ public void onEmergencyCallConnectionStateChanged( String callId, @Connection.ConnectionState int state) { + if (!mSatelliteController.isSatelliteSupportedViaOem() + && !mSatelliteController.isSatelliteSupportedViaCarrier()) { + logd("onEmergencyCallConnectionStateChanged: satellite is not supported"); + return; + } Pair<String, Integer> argument = new Pair<>(callId, state); sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED, argument)); } - private void handleEmergencyCallStartedEvent(@NonNull Pair<Connection, Phone> arg) { - mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mReceiverForRequestIsSatelliteAllowedForCurrentLocation); - if (mPhone != null) { - logd("handleEmergencyCallStartedEvent: new emergency call started while there is " - + " an ongoing call"); - unregisterForInterestedStateChangedEvents(mPhone); + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected ComponentName getDefaultSmsApp() { + return SmsApplication.getDefaultSmsApplication(mContext, false); + } + + private void handleEmergencyCallStartedEvent(@NonNull Connection connection) { + if (sendEventDisplayEmergencyMessageForcefully(connection)) { + return; + } + if (mEmergencyConnection == null) { + mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mReceiverForRequestIsSatelliteAllowedForCurrentLocation); + handleStateChangedEventForHysteresisTimer(); + registerForInterestedStateChangedEvents(); } - mPhone = arg.second; - mEmergencyConnection = arg.first; - mCellularServiceState.set(mPhone.getServiceState().getState()); - mIsImsRegistered.set(mPhone.isImsRegistered()); - handleStateChangedEventForHysteresisTimer(); - registerForInterestedStateChangedEvents(mPhone); + mEmergencyConnection = connection; } private void handleSatelliteProvisionStateChangedEvent(boolean provisioned) { @@ -253,19 +261,49 @@ public class SatelliteSOSMessageRecommender extends Handler { } private void handleTimeoutEvent() { + /** + * The device might be connected to satellite after the emergency call started. Thus, we + * need to do this check again so that we will have higher chance of sending the event + * EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer. + */ + updateSatelliteViaCarrierAvailability(); + boolean isDialerNotified = false; - if (!mIsImsRegistered.get() && !isCellularAvailable() + if (!isImsRegistered() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned() + && (isSatelliteViaOemAvailable() || isSatelliteViaCarrierAvailable()) && shouldTrackCall(mEmergencyConnection.getState())) { - logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); - mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); + logd("handleTimeoutEvent: Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer"); + Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(); + mEmergencyConnection.sendConnectionEvent( + TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras); isDialerNotified = true; + } + logd("handleTimeoutEvent: isImsRegistered=" + isImsRegistered() + + ", isCellularAvailable=" + isCellularAvailable() + + ", mIsSatelliteAllowedInCurrentLocation=" + + mIsSatelliteAllowedInCurrentLocation.get() + + ", shouldTrackCall=" + shouldTrackCall(mEmergencyConnection.getState())); reportEsosRecommenderDecision(isDialerNotified); cleanUpResources(); } + private void updateSatelliteViaCarrierAvailability() { + if (!mIsSatelliteConnectedViaCarrierWithinHysteresisTime.get()) { + mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set( + mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + } + } + + private boolean isSatelliteViaOemAvailable() { + return mSatelliteController.isSatelliteViaOemProvisioned(); + } + + private boolean isSatelliteViaCarrierAvailable() { + return mIsSatelliteConnectedViaCarrierWithinHysteresisTime.get(); + } + private void handleEmergencyCallConnectionStateChangedEvent( @NonNull Pair<String, Integer> arg) { if (mEmergencyConnection == null) { @@ -294,78 +332,117 @@ public class SatelliteSOSMessageRecommender extends Handler { } } - private void handleImsRegistrationStateChangedEvent(boolean registered) { - if (registered != mIsImsRegistered.get()) { - mIsImsRegistered.set(registered); - handleStateChangedEventForHysteresisTimer(); - } - } - - private void handleCellularServiceStateChangedEvent(@NonNull ServiceState serviceState) { - int state = serviceState.getState(); - if (mCellularServiceState.get() != state) { - mCellularServiceState.set(state); - handleStateChangedEventForHysteresisTimer(); - } - } - private void reportEsosRecommenderDecision(boolean isDialerNotified) { SatelliteStats.getInstance().onSatelliteSosMessageRecommender( new SatelliteStats.SatelliteSosMessageRecommenderParams.Builder() .setDisplaySosMessageSent(isDialerNotified) .setCountOfTimerStarted(mCountOfTimerStarted) - .setImsRegistered(mIsImsRegistered.get()) - .setCellularServiceState(mCellularServiceState.get()) + .setImsRegistered(isImsRegistered()) + .setCellularServiceState(getBestCellularServiceState()) + .setIsMultiSim(isMultiSim()) + .setRecommendingHandoverType(getEmergencyCallToSatelliteHandoverType()) + .setIsSatelliteAllowedInCurrentLocation( + mIsSatelliteAllowedInCurrentLocation.get()) .build()); } private void cleanUpResources() { stopTimer(); - if (mPhone != null) { - unregisterForInterestedStateChangedEvents(mPhone); - mPhone = null; + if (mEmergencyConnection != null) { + unregisterForInterestedStateChangedEvents(); } mEmergencyConnection = null; mCountOfTimerStarted = 0; } - private void registerForInterestedStateChangedEvents(@NonNull Phone phone) { + private void registerForInterestedStateChangedEvents() { mSatelliteController.registerForSatelliteProvisionStateChanged( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback); - phone.registerForServiceStateChanged(this, EVENT_CELLULAR_SERVICE_STATE_CHANGED, null); - registerForImsRegistrationStateChanged(phone); + for (Phone phone : PhoneFactory.getPhones()) { + phone.registerForServiceStateChanged( + this, EVENT_SERVICE_STATE_CHANGED, null); + registerForImsRegistrationStateChanged(phone); + } } private void registerForImsRegistrationStateChanged(@NonNull Phone phone) { ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance( phone.getContext(), phone.getPhoneId()); try { - imsManager.addRegistrationCallback(mImsRegistrationCallback, this::post); + imsManager.addRegistrationCallback( + getOrCreateImsRegistrationCallback(phone.getPhoneId()), this::post); } catch (ImsException ex) { loge("registerForImsRegistrationStateChanged: ex=" + ex); } } - private void unregisterForInterestedStateChangedEvents(@NonNull Phone phone) { + private void unregisterForInterestedStateChangedEvents() { mSatelliteController.unregisterForSatelliteProvisionStateChanged( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback); - phone.unregisterForServiceStateChanged(this); - unregisterForImsRegistrationStateChanged(phone); + for (Phone phone : PhoneFactory.getPhones()) { + phone.unregisterForServiceStateChanged(this); + unregisterForImsRegistrationStateChanged(phone); + } } private void unregisterForImsRegistrationStateChanged(@NonNull Phone phone) { - ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance( - phone.getContext(), phone.getPhoneId()); - imsManager.removeRegistrationListener(mImsRegistrationCallback); + if (mImsRegistrationCallbacks.contains(phone.getPhoneId())) { + ImsManager imsManager = + (mImsManager != null) ? mImsManager : ImsManager.getInstance( + phone.getContext(), phone.getPhoneId()); + imsManager.removeRegistrationListener( + mImsRegistrationCallbacks.get(phone.getPhoneId())); + } else { + loge("Phone ID=" + phone.getPhoneId() + " was not registered with ImsManager"); + } } private boolean isCellularAvailable() { - return (mCellularServiceState.get() == ServiceState.STATE_IN_SERVICE - || mCellularServiceState.get() == ServiceState.STATE_EMERGENCY_ONLY); + for (Phone phone : PhoneFactory.getPhones()) { + ServiceState serviceState = phone.getServiceState(); + if (serviceState != null) { + int state = serviceState.getState(); + if ((state == STATE_IN_SERVICE || state == STATE_EMERGENCY_ONLY) + && !serviceState.isUsingNonTerrestrialNetwork()) { + return true; + } + } + } + return false; + } + + /** + * @return {@link ServiceState#STATE_IN_SERVICE} if any subscription is in this state; else + * {@link ServiceState#STATE_EMERGENCY_ONLY} if any subscription is in this state; else + * {@link ServiceState#STATE_OUT_OF_SERVICE}. + */ + private int getBestCellularServiceState() { + boolean isStateOutOfService = true; + for (Phone phone : PhoneFactory.getPhones()) { + ServiceState serviceState = phone.getServiceState(); + if (serviceState != null) { + int state = serviceState.getState(); + if (!serviceState.isUsingNonTerrestrialNetwork()) { + if ((state == STATE_IN_SERVICE)) { + return STATE_IN_SERVICE; + } else if (state == STATE_EMERGENCY_ONLY) { + isStateOutOfService = false; + } + } + } + } + return isStateOutOfService ? STATE_OUT_OF_SERVICE : STATE_EMERGENCY_ONLY; } - private void handleStateChangedEventForHysteresisTimer() { - if (!mIsImsRegistered.get() && !isCellularAvailable()) { + private boolean isImsRegistered() { + for (Phone phone : PhoneFactory.getPhones()) { + if (phone.isImsRegistered()) return true; + } + return false; + } + + private synchronized void handleStateChangedEventForHysteresisTimer() { + if (!isImsRegistered() && !isCellularAvailable()) { startTimer(); } else { stopTimer(); @@ -384,10 +461,61 @@ public class SatelliteSOSMessageRecommender extends Handler { removeMessages(EVENT_TIME_OUT); } - private static long getEmergencyCallToSosMsgHysteresisTimeoutMillis() { - return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, - EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS, - DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + private static long getEmergencyCallWaitForConnectionTimeoutMillis(@NonNull Context context) { + return context.getResources().getInteger( + R.integer.config_emergency_call_wait_for_connection_timeout_millis); + } + + /** + * @return The Pair(PackageName, ClassName) of the oem-enabled satellite handover app. + */ + @NonNull + private static Pair<String, String> getOemEnabledSatelliteHandoverAppFromOverlayConfig( + @NonNull Context context) { + String app = null; + try { + app = context.getResources().getString( + R.string.config_oem_enabled_satellite_sos_handover_app); + } catch (Resources.NotFoundException ex) { + loge("getOemEnabledSatelliteHandoverAppFromOverlayConfig: ex=" + ex); + } + if (TextUtils.isEmpty(app) && isMockModemAllowed()) { + logd("getOemEnabledSatelliteHandoverAppFromOverlayConfig: Read " + + "config_oem_enabled_satellite_sos_handover_app from device config"); + app = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, + "config_oem_enabled_satellite_sos_handover_app", ""); + } + if (TextUtils.isEmpty(app)) return new Pair<>("", ""); + + String[] appComponent = app.split(";"); + if (appComponent.length == 2) { + return new Pair<>(appComponent[0], appComponent[1]); + } else { + loge("getOemEnabledSatelliteHandoverAppFromOverlayConfig: invalid configured app=" + + app); + } + return new Pair<>("", ""); + } + + + @Nullable + private static String getSatelliteEmergencyHandoverIntentActionFromOverlayConfig( + @NonNull Context context) { + String action; + try { + action = context.getResources().getString( + R.string.config_satellite_emergency_handover_intent_action); + } catch (Resources.NotFoundException ex) { + loge("getSatelliteEmergencyHandoverIntentFilterActionFromOverlayConfig: ex=" + ex); + action = null; + } + if (TextUtils.isEmpty(action) && isMockModemAllowed()) { + logd("getSatelliteEmergencyHandoverIntentActionFromOverlayConfig: Read " + + "config_satellite_emergency_handover_intent_action from device config"); + action = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, + "config_satellite_emergency_handover_intent_action", null); + } + return action; } private boolean shouldTrackCall(int connectionState) { @@ -400,6 +528,110 @@ public class SatelliteSOSMessageRecommender extends Handler { && connectionState != Connection.STATE_DISCONNECTED); } + @NonNull + private RegistrationManager.RegistrationCallback getOrCreateImsRegistrationCallback( + int phoneId) { + RegistrationManager.RegistrationCallback callback = + mImsRegistrationCallbacks.get(phoneId); + if (callback == null) { + callback = new RegistrationManager.RegistrationCallback() { + @Override + public void onRegistered(ImsRegistrationAttributes attributes) { + sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED)); + } + + @Override + public void onUnregistered(ImsReasonInfo info) { + sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED)); + } + }; + mImsRegistrationCallbacks.put(phoneId, callback); + } + return callback; + } + + @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage() { + int handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS; + Pair<String, String> oemSatelliteMessagingApp = + getOemEnabledSatelliteHandoverAppFromOverlayConfig(mContext); + String packageName = oemSatelliteMessagingApp.first; + String className = oemSatelliteMessagingApp.second; + String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext); + + if (isSatelliteViaCarrierAvailable() + || isEmergencyCallToSatelliteHandoverTypeT911Enforced()) { + ComponentName defaultSmsAppComponent = getDefaultSmsApp(); + handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911; + packageName = defaultSmsAppComponent.getPackageName(); + className = defaultSmsAppComponent.getClassName(); + } + logd("EVENT_DISPLAY_EMERGENCY_MESSAGE: handoverType=" + handoverType + ", packageName=" + + packageName + ", className=" + className + ", action=" + action); + + Bundle result = new Bundle(); + result.putInt(EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE, handoverType); + if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) { + result.putParcelable(EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT, + createHandoverAppLaunchPendingIntent(packageName, className, action)); + } + return result; + } + + @NonNull private PendingIntent createHandoverAppLaunchPendingIntent( + @NonNull String packageName, @NonNull String className, @Nullable String action) { + Intent intent = new Intent(action); + intent.setComponent(new ComponentName(packageName, className)); + return PendingIntent.getActivity(mContext, 0, intent, + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); + } + + private boolean isEmergencyCallToSatelliteHandoverTypeT911Enforced() { + return (mSatelliteController.getEnforcedEmergencyCallToSatelliteHandoverType() + == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911); + } + + private boolean sendEventDisplayEmergencyMessageForcefully(@NonNull Connection connection) { + if (mSatelliteController.getEnforcedEmergencyCallToSatelliteHandoverType() + == INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE) { + return false; + } + + long delaySeconds = mSatelliteController.getDelayInSendingEventDisplayEmergencyMessage(); + sendMessageDelayed( + obtainMessage(CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY, connection), + delaySeconds * 1000); + return true; + } + + private void handleCmdSendEventDisplayEmergencyMessageForcefully( + @NonNull Connection connection) { + logd("Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer forcefully."); + Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(); + connection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras); + } + + private boolean isMultiSim() { + TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); + if (telephonyManager == null) { + loge("isMultiSim: telephonyManager is null"); + return false; + } + return telephonyManager.isMultiSimEnabled(); + } + + private int getEmergencyCallToSatelliteHandoverType() { + if (isSatelliteViaCarrierAvailable()) { + return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911; + } else { + return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS; + } + } + + private static boolean isMockModemAllowed() { + return (SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false) + || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false)); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index 151b69dd77..0e6f706d92 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.satellite; import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE; import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE; +import static java.util.stream.Collectors.joining; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -29,23 +31,23 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.satellite.AntennaPosition; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.stub.NTRadioTechnology; -import android.telephony.satellite.stub.SatelliteError; import android.telephony.satellite.stub.SatelliteModemState; +import android.telephony.satellite.stub.SatelliteResult; -import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RILUtils; import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -81,53 +83,51 @@ public class SatelliteServiceUtils { /** * Convert satellite error from service definition to framework definition. * @param error The SatelliteError from the satellite service. - * @return The converted SatelliteError for the framework. + * @return The converted SatelliteResult for the framework. */ - @SatelliteManager.SatelliteError public static int fromSatelliteError(int error) { + @SatelliteManager.SatelliteResult public static int fromSatelliteError(int error) { switch (error) { - case SatelliteError.ERROR_NONE: - return SatelliteManager.SATELLITE_ERROR_NONE; - case SatelliteError.SATELLITE_ERROR: - return SatelliteManager.SATELLITE_ERROR; - case SatelliteError.SERVER_ERROR: - return SatelliteManager.SATELLITE_SERVER_ERROR; - case SatelliteError.SERVICE_ERROR: - return SatelliteManager.SATELLITE_SERVICE_ERROR; - case SatelliteError.MODEM_ERROR: - return SatelliteManager.SATELLITE_MODEM_ERROR; - case SatelliteError.NETWORK_ERROR: - return SatelliteManager.SATELLITE_NETWORK_ERROR; - case SatelliteError.INVALID_TELEPHONY_STATE: - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - case SatelliteError.INVALID_MODEM_STATE: - return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; - case SatelliteError.INVALID_ARGUMENTS: - return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; - case SatelliteError.REQUEST_FAILED: - return SatelliteManager.SATELLITE_REQUEST_FAILED; - case SatelliteError.RADIO_NOT_AVAILABLE: - return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; - case SatelliteError.REQUEST_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; - case SatelliteError.NO_RESOURCES: - return SatelliteManager.SATELLITE_NO_RESOURCES; - case SatelliteError.SERVICE_NOT_PROVISIONED: - return SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; - case SatelliteError.SERVICE_PROVISION_IN_PROGRESS: - return SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; - case SatelliteError.REQUEST_ABORTED: - return SatelliteManager.SATELLITE_REQUEST_ABORTED; - case SatelliteError.SATELLITE_ACCESS_BARRED: - return SatelliteManager.SATELLITE_ACCESS_BARRED; - case SatelliteError.NETWORK_TIMEOUT: - return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; - case SatelliteError.SATELLITE_NOT_REACHABLE: - return SatelliteManager.SATELLITE_NOT_REACHABLE; - case SatelliteError.NOT_AUTHORIZED: - return SatelliteManager.SATELLITE_NOT_AUTHORIZED; + case SatelliteResult.SATELLITE_RESULT_SUCCESS: + return SatelliteManager.SATELLITE_RESULT_SUCCESS; + case SatelliteResult.SATELLITE_RESULT_ERROR: + return SatelliteManager.SATELLITE_RESULT_ERROR; + case SatelliteResult.SATELLITE_RESULT_SERVER_ERROR: + return SatelliteManager.SATELLITE_RESULT_SERVER_ERROR; + case SatelliteResult.SATELLITE_RESULT_SERVICE_ERROR: + return SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR; + case SatelliteResult.SATELLITE_RESULT_MODEM_ERROR: + return SatelliteManager.SATELLITE_RESULT_MODEM_ERROR; + case SatelliteResult.SATELLITE_RESULT_NETWORK_ERROR: + return SatelliteManager.SATELLITE_RESULT_NETWORK_ERROR; + case SatelliteResult.SATELLITE_RESULT_INVALID_MODEM_STATE: + return SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE; + case SatelliteResult.SATELLITE_RESULT_INVALID_ARGUMENTS: + return SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS; + case SatelliteResult.SATELLITE_RESULT_REQUEST_FAILED: + return SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED; + case SatelliteResult.SATELLITE_RESULT_RADIO_NOT_AVAILABLE: + return SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE; + case SatelliteResult.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; + case SatelliteResult.SATELLITE_RESULT_NO_RESOURCES: + return SatelliteManager.SATELLITE_RESULT_NO_RESOURCES; + case SatelliteResult.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED: + return SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED; + case SatelliteResult.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS: + return SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS; + case SatelliteResult.SATELLITE_RESULT_REQUEST_ABORTED: + return SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED; + case SatelliteResult.SATELLITE_RESULT_ACCESS_BARRED: + return SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED; + case SatelliteResult.SATELLITE_RESULT_NETWORK_TIMEOUT: + return SatelliteManager.SATELLITE_RESULT_NETWORK_TIMEOUT; + case SatelliteResult.SATELLITE_RESULT_NOT_REACHABLE: + return SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE; + case SatelliteResult.SATELLITE_RESULT_NOT_AUTHORIZED: + return SatelliteManager.SATELLITE_RESULT_NOT_AUTHORIZED; } loge("Received invalid satellite service error: " + error); - return SatelliteManager.SATELLITE_SERVICE_ERROR; + return SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR; } /** @@ -150,6 +150,10 @@ public class SatelliteServiceUtils { return SatelliteManager.SATELLITE_MODEM_STATE_OFF; case SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE: return SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; + case SatelliteModemState.SATELLITE_MODEM_STATE_NOT_CONNECTED: + return SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED; + case SatelliteModemState.SATELLITE_MODEM_STATE_CONNECTED: + return SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; default: loge("Received invalid modem state: " + modemState); return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; @@ -209,6 +213,16 @@ public class SatelliteServiceUtils { } /** + * Convert non-terrestrial signal strength from service definition to framework definition. + * @param ntnSignalStrength The non-terrestrial signal strength from the satellite service. + * @return The converted non-terrestrial signal strength for the framework. + */ + @Nullable public static NtnSignalStrength fromNtnSignalStrength( + android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) { + return new NtnSignalStrength(ntnSignalStrength.signalStrengthLevel); + } + + /** * Convert SatelliteDatagram from framework definition to service definition. * @param datagram The SatelliteDatagram from the framework. * @return The converted SatelliteDatagram for the satellite service. @@ -222,25 +236,21 @@ public class SatelliteServiceUtils { } /** - * Get the {@link SatelliteManager.SatelliteError} from the provided result. + * Get the {@link SatelliteManager.SatelliteResult} from the provided result. * * @param ar AsyncResult used to determine the error code. * @param caller The satellite request. * - * @return The {@link SatelliteManager.SatelliteError} error code from the request. + * @return The {@link SatelliteManager.SatelliteResult} error code from the request. */ - @SatelliteManager.SatelliteError public static int getSatelliteError(@NonNull AsyncResult ar, + @SatelliteManager.SatelliteResult public static int getSatelliteError(@NonNull AsyncResult ar, @NonNull String caller) { int errorCode; if (ar.exception == null) { - errorCode = SatelliteManager.SATELLITE_ERROR_NONE; + errorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; } else { - errorCode = SatelliteManager.SATELLITE_ERROR; - if (ar.exception instanceof CommandException) { - CommandException.Error error = ((CommandException) ar.exception).getCommandError(); - errorCode = RILUtils.convertToSatelliteError(error); - loge(caller + " CommandException: " + ar.exception); - } else if (ar.exception instanceof SatelliteManager.SatelliteException) { + errorCode = SatelliteManager.SATELLITE_RESULT_ERROR; + if (ar.exception instanceof SatelliteManager.SatelliteException) { errorCode = ((SatelliteManager.SatelliteException) ar.exception).getErrorCode(); loge(caller + " SatelliteException: " + ar.exception); } else { @@ -274,58 +284,6 @@ public class SatelliteServiceUtils { } /** - * Expected format of each input string in the array: "PLMN_1:service_1,service_2,..." - * - * @return The map of supported services with key: PLMN, value: set of services supported by - * the PLMN. - */ - @NonNull - @NetworkRegistrationInfo.ServiceType - public static Map<String, Set<Integer>> parseSupportedSatelliteServices( - String[] supportedSatelliteServicesStrArray) { - Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); - if (supportedSatelliteServicesStrArray == null - || supportedSatelliteServicesStrArray.length == 0) { - return supportedServicesMap; - } - - for (String supportedServicesPerPlmnStr : supportedSatelliteServicesStrArray) { - String[] pairOfPlmnAndsupportedServicesStr = - supportedServicesPerPlmnStr.split(":"); - if (pairOfPlmnAndsupportedServicesStr != null - && (pairOfPlmnAndsupportedServicesStr.length == 1 - || pairOfPlmnAndsupportedServicesStr.length == 2)) { - String plmn = pairOfPlmnAndsupportedServicesStr[0]; - Set<Integer> supportedServicesSet = new HashSet<>(); - if (pairOfPlmnAndsupportedServicesStr.length == 2) { - String[] supportedServicesStrArray = - pairOfPlmnAndsupportedServicesStr[1].split(","); - for (String service : supportedServicesStrArray) { - try { - int serviceType = Integer.parseInt(service); - if (isServiceTypeValid(serviceType)) { - supportedServicesSet.add(serviceType); - } else { - loge("parseSupportedSatelliteServices: invalid serviceType=" - + serviceType); - } - } catch (NumberFormatException e) { - loge("parseSupportedSatelliteServices: supportedServicesPerPlmnStr=" - + supportedServicesPerPlmnStr + ", service=" + service - + ", e=" + e); - } - } - } - supportedServicesMap.put(plmn, supportedServicesSet); - } else { - loge("parseSupportedSatelliteServices: invalid format input, " - + "supportedServicesPerPlmnStr=" + supportedServicesPerPlmnStr); - } - } - return supportedServicesMap; - } - - /** * Expected format of the input dictionary bundle is: * <ul> * <li>Key: PLMN string.</li> @@ -353,41 +311,23 @@ public class SatelliteServiceUtils { + " for plmn=" + plmn); } } + logd("parseSupportedSatelliteServices: plmn=" + plmn + ", supportedServicesSet=" + + supportedServicesSet.stream().map(String::valueOf).collect( + joining(","))); supportedServicesMap.put(plmn, supportedServicesSet); } return supportedServicesMap; } /** - * For the PLMN that exists in both {@code providerSupportedServices} and - * {@code carrierSupportedServices}, the supported services will be the intersection of the two - * sets. For the PLMN that is present in {@code providerSupportedServices} but not in - * {@code carrierSupportedServices}, the provider supported services will be used. The rest - * will not be used. - * - * @param providerSupportedServices Satellite provider supported satellite services. - * @param carrierSupportedServices Carrier supported satellite services. - * @return The supported satellite services by the device for the corresponding carrier and the - * satellite provider. + * Merge two string lists into one such that the result list does not have any duplicate items. */ @NonNull - @NetworkRegistrationInfo.ServiceType - public static Map<String, Set<Integer>> mergeSupportedSatelliteServices( - @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> - providerSupportedServices, - @NonNull @NetworkRegistrationInfo.ServiceType Map<String, Set<Integer>> - carrierSupportedServices) { - Map<String, Set<Integer>> supportedServicesMap = new HashMap<>(); - for (Map.Entry<String, Set<Integer>> entry : providerSupportedServices.entrySet()) { - Set<Integer> supportedServices = new HashSet<>(entry.getValue()); - if (carrierSupportedServices.containsKey(entry.getKey())) { - supportedServices.retainAll(carrierSupportedServices.get(entry.getKey())); - } - if (!supportedServices.isEmpty()) { - supportedServicesMap.put(entry.getKey(), supportedServices); - } - } - return supportedServicesMap; + public static List<String> mergeStrLists(List<String> strList1, List<String> strList2) { + Set<String> mergedStrSet = new HashSet<>(); + mergedStrSet.addAll(strList1); + mergedStrSet.addAll(strList2); + return mergedStrSet.stream().toList(); } private static boolean isServiceTypeValid(int serviceType) { @@ -403,6 +343,15 @@ public class SatelliteServiceUtils { return PhoneFactory.getPhone(0); } + /** + * Return phone associated with subscription ID. + * + * @return phone associated with {@code subId} or {@code null} if it doesn't exist. + */ + public static @Nullable Phone getPhone(int subId) { + return PhoneFactory.getPhone(subId); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 36ad2503d0..d0497ebe34 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS; @@ -23,6 +24,7 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TR import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -30,13 +32,13 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.AsyncResult; import android.os.Build; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.SystemProperties; -import android.provider.DeviceConfig; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; @@ -46,6 +48,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.util.State; @@ -95,6 +98,9 @@ public class SatelliteSessionController extends StateMachine { private static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 1; private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2; private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3; + private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 4; + private static final int EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE = 5; + protected static final int EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT = 6; private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute @@ -117,14 +123,21 @@ public class SatelliteSessionController extends StateMachine { @NonNull private final IdleState mIdleState = new IdleState(); @NonNull private final TransferringState mTransferringState = new TransferringState(); @NonNull private final ListeningState mListeningState = new ListeningState(); + @NonNull private final NotConnectedState mNotConnectedState = new NotConnectedState(); + @NonNull private final ConnectedState mConnectedState = new ConnectedState(); @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected AtomicBoolean mIsSendingTriggeredDuringTransferringState; private long mSatelliteStayAtListeningFromSendingMillis; private long mSatelliteStayAtListeningFromReceivingMillis; + private long mSatelliteNbIotInactivityTimeoutMillis; private final ConcurrentHashMap<IBinder, ISatelliteStateCallback> mListeners; @SatelliteManager.SatelliteModemState private int mCurrentState; final boolean mIsSatelliteSupported; private boolean mIsDemoMode = false; + @GuardedBy("mLock") + @NonNull private boolean mIsDisableCellularModemInProgress = false; + @NonNull private final SatelliteController mSatelliteController; + @NonNull private final DatagramController mDatagramController; /** * @return The singleton instance of SatelliteSessionController. @@ -148,9 +161,7 @@ public class SatelliteSessionController extends StateMachine { @NonNull Context context, @NonNull Looper looper, boolean isSatelliteSupported) { if (sInstance == null) { sInstance = new SatelliteSessionController(context, looper, isSatelliteSupported, - SatelliteModemInterface.getInstance(), - getSatelliteStayAtListeningFromSendingMillis(), - getSatelliteStayAtListeningFromReceivingMillis()); + SatelliteModemInterface.getInstance()); } else { if (isSatelliteSupported != sInstance.mIsSatelliteSupported) { Rlog.e(TAG, "New satellite support state " + isSatelliteSupported @@ -168,23 +179,22 @@ public class SatelliteSessionController extends StateMachine { * @param looper The looper associated with the handler of this class. * @param isSatelliteSupported Whether satellite is supported on the device. * @param satelliteModemInterface The singleton of SatelliteModemInterface. - * @param satelliteStayAtListeningFromSendingMillis The duration to stay at listening mode when - * transitioning from sending mode. - * @param satelliteStayAtListeningFromReceivingMillis The duration to stay at listening mode - * when transitioning from receiving mode. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected SatelliteSessionController(@NonNull Context context, @NonNull Looper looper, boolean isSatelliteSupported, - @NonNull SatelliteModemInterface satelliteModemInterface, - long satelliteStayAtListeningFromSendingMillis, - long satelliteStayAtListeningFromReceivingMillis) { + @NonNull SatelliteModemInterface satelliteModemInterface) { super(TAG, looper); mContext = context; mSatelliteModemInterface = satelliteModemInterface; - mSatelliteStayAtListeningFromSendingMillis = satelliteStayAtListeningFromSendingMillis; - mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; + mSatelliteController = SatelliteController.getInstance(); + mDatagramController = DatagramController.getInstance(); + mSatelliteStayAtListeningFromSendingMillis = getSatelliteStayAtListeningFromSendingMillis(); + mSatelliteStayAtListeningFromReceivingMillis = + getSatelliteStayAtListeningFromReceivingMillis(); + mSatelliteNbIotInactivityTimeoutMillis = + getSatelliteNbIotInactivityTimeoutMillis(); mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; @@ -211,6 +221,8 @@ public class SatelliteSessionController extends StateMachine { addState(mIdleState); addState(mTransferringState); addState(mListeningState, mTransferringState); + addState(mNotConnectedState); + addState(mConnectedState); setInitialState(isSatelliteSupported); start(); } @@ -245,6 +257,17 @@ public class SatelliteSessionController extends StateMachine { } /** + * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController} + * that the satellite modem state has changed. + * + * @param state The current state of the satellite modem. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { + sendMessage(EVENT_SATELLITE_MODEM_STATE_CHANGED, state); + } + + /** * Registers for modem state changed from satellite modem. * * @param callback The callback to handle the satellite modem state changed event. @@ -289,9 +312,12 @@ public class SatelliteSessionController extends StateMachine { getSatelliteStayAtListeningFromSendingMillis(); mSatelliteStayAtListeningFromReceivingMillis = getSatelliteStayAtListeningFromReceivingMillis(); + mSatelliteNbIotInactivityTimeoutMillis = + getSatelliteNbIotInactivityTimeoutMillis(); } else { mSatelliteStayAtListeningFromSendingMillis = timeoutMillis; mSatelliteStayAtListeningFromReceivingMillis = timeoutMillis; + mSatelliteNbIotInactivityTimeoutMillis = timeoutMillis; } return true; @@ -363,6 +389,7 @@ public class SatelliteSessionController extends StateMachine { public void enter() { if (DBG) logd("Entering UnavailableState"); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE); } @Override @@ -379,7 +406,11 @@ public class SatelliteSessionController extends StateMachine { mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); + synchronized (mLock) { + mIsDisableCellularModemInProgress = false; + } unbindService(); + stopNbIotInactivityTimer(); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -404,7 +435,11 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { - transitionTo(mIdleState); + if (mSatelliteController.isSatelliteAttachRequired()) { + transitionTo(mNotConnectedState); + } else { + transitionTo(mIdleState); + } } } } @@ -415,6 +450,7 @@ public class SatelliteSessionController extends StateMachine { if (DBG) logd("Entering IdleState"); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); + stopNbIotInactivityTimer(); //Enable Cellular Modem scanning mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); @@ -430,6 +466,10 @@ public class SatelliteSessionController extends StateMachine { case EVENT_SATELLITE_ENABLED_STATE_CHANGED: handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "IdleState"); break; + case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE: + handleEventDisableCellularModemWhileSatelliteModeIsOnDone( + (AsyncResult) msg.obj); + break; } // Ignore all unexpected events. return HANDLED; @@ -440,15 +480,61 @@ public class SatelliteSessionController extends StateMachine { if ((datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) || (datagramTransferState.receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING)) { - transitionTo(mTransferringState); + if (mSatelliteController.isSatelliteAttachRequired()) { + loge("Unexpected transferring state received for NB-IOT NTN"); + } else { + transitionTo(mTransferringState); + } + } else if ((datagramTransferState.sendState + == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT) + || (datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT)) { + if (mSatelliteController.isSatelliteAttachRequired()) { + disableCellularModemWhileSatelliteModeIsOn(); + } else { + loge("Unexpected transferring state received for non-NB-IOT NTN"); + } + } + } + + private void handleEventDisableCellularModemWhileSatelliteModeIsOnDone( + @NonNull AsyncResult result) { + synchronized (mLock) { + if (mIsDisableCellularModemInProgress) { + int error = SatelliteServiceUtils.getSatelliteError( + result, "DisableCellularModemWhileSatelliteModeIsOnDone"); + if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) { + transitionTo(mNotConnectedState); + } + mIsDisableCellularModemInProgress = false; + } else { + loge("DisableCellularModemWhileSatelliteModeIsOn is not in progress"); + } + } + } + + private void disableCellularModemWhileSatelliteModeIsOn() { + synchronized (mLock) { + if (mIsDisableCellularModemInProgress) { + logd("Cellular scanning is already being disabled"); + return; + } + + mIsDisableCellularModemInProgress = true; + Message onCompleted = + obtainMessage(EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE); + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, + onCompleted); } } @Override public void exit() { if (DBG) logd("Exiting IdleState"); - //Disable Cellular Modem Scanning - mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); + if (!mSatelliteController.isSatelliteAttachRequired()) { + // Disable cellular modem scanning + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); + } } } @@ -456,6 +542,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); + stopNbIotInactivityTimer(); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -470,6 +557,9 @@ public class SatelliteSessionController extends StateMachine { case EVENT_SATELLITE_ENABLED_STATE_CHANGED: handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "TransferringState"); break; + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + handleEventSatelliteModemStateChange(msg.arg1); + break; } // Ignore all unexpected events. return HANDLED; @@ -480,13 +570,26 @@ public class SatelliteSessionController extends StateMachine { if (isSending(datagramTransferState.sendState) || isReceiving( datagramTransferState.receiveState)) { // Stay at transferring state. - } else if ((datagramTransferState.sendState - == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED) - || (datagramTransferState.receiveState - == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED)) { - transitionTo(mIdleState); } else { - transitionTo(mListeningState); + if (mSatelliteController.isSatelliteAttachRequired()) { + transitionTo(mConnectedState); + } else { + if ((datagramTransferState.sendState + == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED) + || (datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED)) { + transitionTo(mIdleState); + } else { + transitionTo(mListeningState); + } + } + } + } + + private void handleEventSatelliteModemStateChange( + @SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) { + transitionTo(mNotConnectedState); } } } @@ -505,6 +608,8 @@ public class SatelliteSessionController extends StateMachine { @Override public void exit() { + if (DBG) logd("Exiting ListeningState"); + removeMessages(EVENT_LISTENING_TIMER_TIMEOUT); updateListeningMode(false); } @@ -549,6 +654,119 @@ public class SatelliteSessionController extends StateMachine { } } + private class NotConnectedState extends State { + @Override + public void enter() { + if (DBG) logd("Entering NotConnectedState"); + + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED; + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + startNbIotInactivityTimer(); + } + + @Override + public void exit() { + if (DBG) logd("Exiting NotConnectedState"); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("NotConnectedState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged( + !(boolean) msg.obj, "NotConnectedState"); + break; + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + handleEventSatelliteModemStateChanged(msg.arg1); + break; + case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT: + transitionTo(mIdleState); + break; + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private void handleEventSatelliteModemStateChanged( + @SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED) { + transitionTo(mConnectedState); + } + } + + private void handleEventDatagramTransferStateChanged( + @NonNull DatagramTransferState datagramTransferState) { + if (datagramTransferState.sendState + == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT + || datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT) { + stopNbIotInactivityTimer(); + } else if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE + && datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) { + startNbIotInactivityTimer(); + } + } + } + + private class ConnectedState extends State { + @Override + public void enter() { + if (DBG) logd("Entering ConnectedState"); + + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + startNbIotInactivityTimer(); + } + + @Override + public void exit() { + if (DBG) logd("Exiting ConnectedState"); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("ConnectedState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged( + !(boolean) msg.obj, "ConnectedState"); + break; + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + handleEventSatelliteModemStateChanged(msg.arg1); + break; + case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT: + transitionTo(mIdleState); + break; + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private void handleEventSatelliteModemStateChanged( + @SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED) { + transitionTo(mNotConnectedState); + } + } + + private void handleEventDatagramTransferStateChanged( + @NonNull DatagramTransferState datagramTransferState) { + if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING + || datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) { + transitionTo(mTransferringState); + } + } + } + /** * @return the string for msg.what */ @@ -565,6 +783,15 @@ public class SatelliteSessionController extends StateMachine { case EVENT_SATELLITE_ENABLED_STATE_CHANGED: whatString = "EVENT_SATELLITE_ENABLED_STATE_CHANGED"; break; + case EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE: + whatString = "EVENT_DISABLE_CELLULAR_MODEM_WHILE_SATELLITE_MODE_IS_ON_DONE"; + break; + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + whatString = "EVENT_SATELLITE_MODEM_STATE_CHANGED"; + break; + case EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT: + whatString = "EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT"; + break; default: whatString = "UNKNOWN EVENT " + what; } @@ -580,6 +807,8 @@ public class SatelliteSessionController extends StateMachine { } private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) { + mDatagramController.onSatelliteModemStateChanged(state); + List<ISatelliteStateCallback> toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { @@ -720,23 +949,49 @@ public class SatelliteSessionController extends StateMachine { return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); } - private static long getSatelliteStayAtListeningFromSendingMillis() { - if (sInstance != null && sInstance.isDemoMode()) { + private long getSatelliteStayAtListeningFromSendingMillis() { + if (isDemoMode()) { return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; } else { - return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, - SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, - DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS); + return mContext.getResources().getInteger( + R.integer.config_satellite_stay_at_listening_from_sending_millis); } } - private static long getSatelliteStayAtListeningFromReceivingMillis() { - if (sInstance != null && sInstance.isDemoMode()) { + private long getSatelliteStayAtListeningFromReceivingMillis() { + if (isDemoMode()) { return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; } else { - return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, - SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS, - DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS); + return mContext.getResources().getInteger( + R.integer.config_satellite_stay_at_listening_from_receiving_millis); } } + + private long getSatelliteNbIotInactivityTimeoutMillis() { + return mContext.getResources().getInteger( + R.integer.config_satellite_nb_iot_inactivity_timeout_millis); + } + + private void startNbIotInactivityTimer() { + if (isNbIotInactivityTimerStarted()) { + logd("NB IOT inactivity timer is already started"); + return; + } + + DatagramController datagramController = DatagramController.getInstance(); + if (datagramController.isSendingInIdleState() + && datagramController.isPollingInIdleState()) { + sendMessageDelayed( + EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT, + mSatelliteNbIotInactivityTimeoutMillis); + } + } + + private void stopNbIotInactivityTimer() { + removeMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT); + } + + private boolean isNbIotInactivityTimerStarted() { + return hasMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT); + } } diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java index 7a1de7cfdb..0c18fac562 100644 --- a/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java +++ b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java @@ -178,9 +178,9 @@ public class ControllerMetricsStats { /** Report a counter when an attempt for incoming datagram is failed */ public void reportIncomingDatagramCount( - @NonNull @SatelliteManager.SatelliteError int result) { + @NonNull @SatelliteManager.SatelliteResult int result) { SatelliteStats.SatelliteControllerParams controllerParam; - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + if (result == SatelliteManager.SATELLITE_RESULT_SUCCESS) { controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() .setCountOfIncomingDatagramSuccess(ADD_COUNT) .build(); @@ -194,9 +194,9 @@ public class ControllerMetricsStats { } /** Report a counter when an attempt for de-provision is success or not */ - public void reportProvisionCount(@NonNull @SatelliteManager.SatelliteError int result) { + public void reportProvisionCount(@NonNull @SatelliteManager.SatelliteResult int result) { SatelliteStats.SatelliteControllerParams controllerParam; - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + if (result == SatelliteManager.SATELLITE_RESULT_SUCCESS) { controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() .setCountOfProvisionSuccess(ADD_COUNT) .build(); @@ -210,9 +210,9 @@ public class ControllerMetricsStats { } /** Report a counter when an attempt for de-provision is success or not */ - public void reportDeprovisionCount(@NonNull @SatelliteManager.SatelliteError int result) { + public void reportDeprovisionCount(@NonNull @SatelliteManager.SatelliteResult int result) { SatelliteStats.SatelliteControllerParams controllerParam; - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + if (result == SatelliteManager.SATELLITE_RESULT_SUCCESS) { controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() .setCountOfDeprovisionSuccess(ADD_COUNT) .build(); diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java index 38696aabe2..d48c4880ad 100644 --- a/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java +++ b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java @@ -58,7 +58,7 @@ public class ProvisionMetricsStats { } /** Sets the resultCode for provision metrics */ - public ProvisionMetricsStats setResultCode(@SatelliteManager.SatelliteError int error) { + public ProvisionMetricsStats setResultCode(@SatelliteManager.SatelliteResult int error) { mResultCode = error; return this; } diff --git a/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java index 776ba640b5..6585bec7de 100644 --- a/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java +++ b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java @@ -30,7 +30,7 @@ public class SessionMetricsStats { private static final boolean DBG = false; private static SessionMetricsStats sInstance = null; - private @SatelliteManager.SatelliteError int mInitializationResult; + private @SatelliteManager.SatelliteResult int mInitializationResult; private @SatelliteManager.NTRadioTechnology int mRadioTechnology; private SessionMetricsStats() { @@ -54,7 +54,7 @@ public class SessionMetricsStats { /** Sets the satellite initialization result */ public SessionMetricsStats setInitializationResult( - @SatelliteManager.SatelliteError int result) { + @SatelliteManager.SatelliteResult int result) { logd("setInitializationResult(" + result + ")"); mInitializationResult = result; return this; @@ -81,7 +81,7 @@ public class SessionMetricsStats { } private void initializeSessionMetricsParam() { - mInitializationResult = SatelliteManager.SATELLITE_ERROR_NONE; + mInitializationResult = SatelliteManager.SATELLITE_RESULT_SUCCESS; mRadioTechnology = SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN; } diff --git a/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java new file mode 100644 index 0000000000..f1845c5bdf --- /dev/null +++ b/src/java/com/android/internal/telephony/security/CellularIdentifierDisclosureNotifier.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.security; + +import android.telephony.CellularIdentifierDisclosure; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.telephony.Rlog; + +/** + * Encapsulates logic to emit notifications to the user that their cellular identifiers were + * disclosed in the clear. + * + * <p>This class will either emit notifications through SafetyCenterManager if SafetyCenter exists + * on a device, or it will emit system notifications otherwise. + * + * @hide + */ +public class CellularIdentifierDisclosureNotifier { + + private static final String TAG = "CellularIdentifierDisclosureNotifier"; + private static CellularIdentifierDisclosureNotifier sInstance = null; + private boolean mEnabled = false; + + @VisibleForTesting + public CellularIdentifierDisclosureNotifier() {} + + /** + * Add a CellularIdentifierDisclosure to be tracked by this instance. + * If appropriate, this will trigger a user notification. + */ + public void addDisclosure(CellularIdentifierDisclosure disclosure) { + // TODO (b/308985417) this is a stub method for now. Logic + // for tracking disclosures and emitting notifications will flow + // from here. + Rlog.d(TAG, "Identifier disclosure reported: " + disclosure); + } + + /** + * Get a singleton CellularIdentifierDisclosureNotifier. + */ + public static synchronized CellularIdentifierDisclosureNotifier getInstance() { + if (sInstance == null) { + sInstance = new CellularIdentifierDisclosureNotifier(); + } + + return sInstance; + } + + /** + * Re-enable if previously disabled. This means that {@code addDisclsoure} will start tracking + * disclosures again and potentially emitting notifications. + */ + public void enable() { + Rlog.d(TAG, "enabled"); + mEnabled = true; + } + + /** + * Clear all internal state and prevent further notifications until optionally re-enabled. + * This can be used to in response to a user disabling the feature to emit notifications. + * If {@code addDisclosure} is called while in a disabled state, disclosures will be dropped. + */ + public void disable() { + Rlog.d(TAG, "disabled"); + mEnabled = false; + } + + public boolean isEnabled() { + return mEnabled; + } +} diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 124437cd6b..7b927f21e3 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -48,6 +48,7 @@ import android.util.LocalLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.util.function.TriConsumer; import com.android.telephony.Rlog; @@ -274,7 +275,13 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getUserId), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_SATELLITE_ENABLED, - SubscriptionInfoInternal::getSatelliteEnabled) + SubscriptionInfoInternal::getSatelliteEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + SubscriptionInfoInternal::getSatelliteAttachEnabledForCarrier), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_NTN, + SubscriptionInfoInternal::getOnlyNonTerrestrialNetwork) ); /** @@ -399,7 +406,13 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionDatabaseManager::setUserId), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_SATELLITE_ENABLED, - SubscriptionDatabaseManager::setSatelliteEnabled) + SubscriptionDatabaseManager::setSatelliteEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + SubscriptionDatabaseManager::setSatelliteAttachEnabledForCarrier), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_NTN, + SubscriptionDatabaseManager::setNtn) ); /** @@ -508,7 +521,9 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, - SimInfo.COLUMN_USER_HANDLE + SimInfo.COLUMN_USER_HANDLE, + SimInfo.COLUMN_SATELLITE_ENABLED, + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER ); /** @@ -529,6 +544,10 @@ public class SubscriptionDatabaseManager extends Handler { @NonNull private final Context mContext; + /** The feature flags */ + @NonNull + private final FeatureFlags mFeatureFlags; + /** The callback used for passing events back to {@link SubscriptionManagerService}. */ @NonNull private final SubscriptionDatabaseManagerCallback mCallback; @@ -619,9 +638,11 @@ public class SubscriptionDatabaseManager extends Handler { * * @param context The context. * @param looper Looper for the handler. + * @param featureFlags The feature flags. * @param callback Subscription database callback. */ public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags, @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); log("Created SubscriptionDatabaseManager."); @@ -630,6 +651,7 @@ public class SubscriptionDatabaseManager extends Handler { mUiccController = UiccController.getInstance(); mAsyncMode = mContext.getResources().getBoolean( com.android.internal.R.bool.config_subscription_database_async_update); + mFeatureFlags = featureFlags; initializeDatabase(); } @@ -1988,6 +2010,40 @@ public class SubscriptionDatabaseManager extends Handler { } /** + * Set whether satellite attach for carrier is enabled or disabled by user. + * + * @param subId Subscription id. + * @param isSatelliteAttachEnabledForCarrier Whether satellite attach for carrier is enabled or + * disabled. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setSatelliteAttachEnabledForCarrier(int subId, + int isSatelliteAttachEnabledForCarrier) { + writeDatabaseAndCacheHelper(subId, + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + isSatelliteAttachEnabledForCarrier, + SubscriptionInfoInternal.Builder::setSatelliteAttachEnabledForCarrier); + } + + /** + * Set whether the subscription is exclusively used for non-terrestrial networks or not. + * + * @param subId Subscription ID. + * @param isNtn {@code 1} if it is a non-terrestrial network subscription. + * {@code 0} otherwise. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setNtn(int subId, int isNtn) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + return; + } + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_NTN, isNtn, + SubscriptionInfoInternal.Builder::setOnlyNonTerrestrialNetwork); + } + + /** * Set whether group of the subscription is disabled. This is only useful if it's a grouped * opportunistic subscription. In this case, if all primary (non-opportunistic) * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), @@ -2243,7 +2299,14 @@ public class SubscriptionDatabaseManager extends Handler { .setUserId(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_USER_HANDLE))) .setSatelliteEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_SATELLITE_ENABLED))); + SimInfo.COLUMN_SATELLITE_ENABLED))) + .setSatelliteAttachEnabledForCarrier(cursor.getInt( + cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER))); + if (mFeatureFlags.oemEnabledSatelliteFlag()) { + builder.setOnlyNonTerrestrialNetwork(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IS_NTN))); + } return builder.build(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index b917698998..f08a659005 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -442,6 +442,18 @@ public class SubscriptionInfoInternal { */ private final int mIsSatelliteEnabled; + /** + * Whether satellite attach for carrier is enabled or disabled by user. + * By default, its disabled. It is intended to use integer to fit the database format. + */ + private final int mIsSatelliteAttachEnabledForCarrier; + + /** + * Whether this subscription is used for communicating with non-terrestrial networks. + * By default, its disabled. It is intended to use integer to fit the database format. + */ + private final int mIsOnlyNonTerrestrialNetwork; + // Below are the fields that do not exist in the SimInfo table. /** * The card ID of the SIM card. This maps uniquely to {@link #mCardString}. @@ -524,6 +536,9 @@ public class SubscriptionInfoInternal { this.mLastUsedTPMessageReference = builder.mLastUsedTPMessageReference; this.mUserId = builder.mUserId; this.mIsSatelliteEnabled = builder.mIsSatelliteEnabled; + this.mIsSatelliteAttachEnabledForCarrier = + builder.mIsSatelliteAttachEnabledForCarrier; + this.mIsOnlyNonTerrestrialNetwork = builder.mIsOnlyNonTerrestrialNetwork; // Below are the fields that do not exist in the SimInfo table. this.mCardId = builder.mCardId; @@ -1128,6 +1143,22 @@ public class SubscriptionInfoInternal { return mIsSatelliteEnabled; } + /** + * @return {@code 1} if satellite attach for carrier is enabled by user. + */ + public int getSatelliteAttachEnabledForCarrier() { + return mIsSatelliteAttachEnabledForCarrier; + } + + /** + * An NTN subscription connects to non-terrestrial networks. + * + * @return {@code 1} if the subscription is for non-terrestrial networks. {@code 0} otherwise. + */ + public int getOnlyNonTerrestrialNetwork() { + return mIsOnlyNonTerrestrialNetwork; + } + // Below are the fields that do not exist in SimInfo table. /** * @return The card ID of the SIM card which contains the subscription. @@ -1197,6 +1228,7 @@ public class SubscriptionInfoInternal { .setUiccApplicationsEnabled(mAreUiccApplicationsEnabled != 0) .setPortIndex(mPortIndex) .setUsageSetting(mUsageSetting) + .setOnlyNonTerrestrialNetwork(mIsOnlyNonTerrestrialNetwork == 1) .build(); } @@ -1253,6 +1285,8 @@ public class SubscriptionInfoInternal { + " numberFromIms=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumberFromIms) + " userId=" + mUserId + " isSatelliteEnabled=" + mIsSatelliteEnabled + + " satellite_attach_enabled_for_carrier=" + mIsSatelliteAttachEnabledForCarrier + + " getOnlyNonTerrestrialNetwork=" + mIsOnlyNonTerrestrialNetwork + " isGroupDisabled=" + mIsGroupDisabled + "]"; } @@ -1308,7 +1342,9 @@ public class SubscriptionInfoInternal { mRcsConfig, that.mRcsConfig) && mAllowedNetworkTypesForReasons.equals( that.mAllowedNetworkTypesForReasons) && mDeviceToDeviceStatusSharingContacts.equals( that.mDeviceToDeviceStatusSharingContacts) && mNumberFromCarrier.equals( - that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms); + that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms) + && mIsSatelliteAttachEnabledForCarrier == that.mIsSatelliteAttachEnabledForCarrier + && mIsOnlyNonTerrestrialNetwork == that.mIsOnlyNonTerrestrialNetwork; } @Override @@ -1329,7 +1365,8 @@ public class SubscriptionInfoInternal { mDeviceToDeviceStatusSharingContacts, mIsNrAdvancedCallingEnabled, mNumberFromCarrier, mNumberFromIms, mPortIndex, mUsageSetting, mLastUsedTPMessageReference, mUserId, - mIsSatelliteEnabled, mCardId, mIsGroupDisabled); + mIsSatelliteEnabled, mCardId, mIsGroupDisabled, + mIsSatelliteAttachEnabledForCarrier, mIsOnlyNonTerrestrialNetwork); result = 31 * result + Arrays.hashCode(mNativeAccessRules); result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules); result = 31 * result + Arrays.hashCode(mRcsConfig); @@ -1690,7 +1727,17 @@ public class SubscriptionInfoInternal { /** * Whether satellite is enabled or not. */ - private int mIsSatelliteEnabled = -1; + private int mIsSatelliteEnabled = 0; + + /** + * Whether satellite attach for carrier is enabled by user. + */ + private int mIsSatelliteAttachEnabledForCarrier = 0; + + /** + * Whether this subscription is used for communicating with non-terrestrial network or not. + */ + private int mIsOnlyNonTerrestrialNetwork = 0; // The following fields do not exist in the SimInfo table. /** @@ -1779,6 +1826,8 @@ public class SubscriptionInfoInternal { mLastUsedTPMessageReference = info.getLastUsedTPMessageReference(); mUserId = info.mUserId; mIsSatelliteEnabled = info.mIsSatelliteEnabled; + mIsSatelliteAttachEnabledForCarrier = info.mIsSatelliteAttachEnabledForCarrier; + mIsOnlyNonTerrestrialNetwork = info.mIsOnlyNonTerrestrialNetwork; // Below are the fields that do not exist in the SimInfo table. mCardId = info.mCardId; mIsGroupDisabled = info.mIsGroupDisabled; @@ -2649,6 +2698,32 @@ public class SubscriptionInfoInternal { return this; } + /** + * Set whether satellite attach for carrier is enabled or disabled by user. + * @param isSatelliteAttachEnabledForCarrier {@code 1} if satellite attach for carrier is + * enabled. + * @return The builder. + */ + @NonNull + public Builder setSatelliteAttachEnabledForCarrier( + @NonNull int isSatelliteAttachEnabledForCarrier) { + mIsSatelliteAttachEnabledForCarrier = isSatelliteAttachEnabledForCarrier; + return this; + } + + /** + * Set whether the subscription is for NTN or not. + * + * @param isOnlyNonTerrestrialNetwork {@code 1} if the subscription is for NTN, {@code 0} + * otherwise. + * @return The builder. + */ + @NonNull + public Builder setOnlyNonTerrestrialNetwork(int isOnlyNonTerrestrialNetwork) { + mIsOnlyNonTerrestrialNetwork = isOnlyNonTerrestrialNetwork; + return this; + } + // Below are the fields that do not exist in the SimInfo table. /** * Set the card ID of the SIM card which contains the subscription. diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ba69d8a7c0..a8d05a334b 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -22,6 +22,7 @@ import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.compat.CompatChanges; @@ -44,9 +45,11 @@ import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.TelephonyServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; @@ -95,6 +98,8 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.IccUtils; @@ -122,6 +127,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; /** * The subscription manager service is the backend service of {@link SubscriptionManager}. @@ -129,6 +135,8 @@ import java.util.stream.IntStream; */ public class SubscriptionManagerService extends ISub.Stub { private static final String LOG_TAG = "SMSVC"; + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; /** Whether enabling verbose debugging message or not. */ private static final boolean VDBG = false; @@ -173,7 +181,9 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, - SimInfo.COLUMN_SATELLITE_ENABLED + SimInfo.COLUMN_SATELLITE_ENABLED, + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + SimInfo.COLUMN_IS_NTN ); /** @@ -185,6 +195,18 @@ public class SubscriptionManagerService extends ISub.Stub { @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L; + /** + * Apps targeting on Android V and beyond can only see subscriptions accessible by them + * according to its user Id. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM) + public static final long FILTER_ACCESSIBLE_SUBS_BY_USER = 296076674L; + + /** Wrap Binder methods for testing. */ + @NonNull + private static final BinderWrapper BINDER_WRAPPER = new BinderWrapper(); + /** Instance of subscription manager service. */ @NonNull private static SubscriptionManagerService sInstance; @@ -193,6 +215,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final Context mContext; + /** Feature flags */ + @NonNull + private final FeatureFlags mFeatureFlags; + /** App Ops manager instance. */ @NonNull private final AppOpsManager mAppOpsManager; @@ -277,6 +303,12 @@ public class SubscriptionManagerService extends ISub.Stub { private final int[] mSimState; /** + * {@code true} if a user profile can only see the SIMs associated with it, unless it possesses + * no SIMs on the device. + */ + private Map<Integer, List<Integer>> mUserIdToAvailableSubs = new ConcurrentHashMap<>(); + + /** * Slot index/subscription map that automatically invalidate cache in * {@link SubscriptionManager}. * @@ -349,6 +381,14 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** Binder Wrapper for test mocking. */ + @VisibleForTesting + public static class BinderWrapper { + @NonNull public UserHandle getCallingUserHandle() { + return Binder.getCallingUserHandle(); + } + } + /** * This is the callback used for listening events from {@link SubscriptionManagerService}. */ @@ -405,10 +445,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @param context The context * @param looper The looper for the handler. */ - public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) { + public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper, + @NonNull FeatureFlags featureFlags) { logl("Created SubscriptionManagerService"); sInstance = this; mContext = context; + mFeatureFlags = featureFlags; mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); @@ -480,7 +522,8 @@ public class SubscriptionManagerService extends ISub.Stub { HandlerThread handlerThread = new HandlerThread(LOG_TAG); handlerThread.start(); mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context, - handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) { + handlerThread.getLooper(), mFeatureFlags, + new SubscriptionDatabaseManagerCallback(mHandler::post) { /** * Called when database has been loaded into the cache. */ @@ -500,6 +543,8 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public void onSubscriptionChanged(int subId) { + updateUserIdToAvailableSubs(); + mSubscriptionManagerServiceCallbacks.forEach( callback -> callback.invokeFromExecutor( () -> callback.onSubscriptionChanged(subId))); @@ -818,6 +863,26 @@ public class SubscriptionManagerService extends ISub.Stub { } /** + * Set whether the subscription ID supports oem satellite or not. + * + * @param subId The subscription ID. + * @param isNtn {@code true} Requested subscription ID supports oem satellite service, + * {@code false} otherwise. + */ + public void setNtn(int subId, boolean isNtn) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + return; + } + + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setNtn(subId, (isNtn ? 1 : 0)); + } catch (IllegalArgumentException e) { + loge("setOnlyNonTerrestrialNetwork: invalid subId=" + subId); + } + } + + /** * Set ISO country code by subscription id. * * @param iso ISO country code associated with the subscription. @@ -1096,7 +1161,16 @@ public class SubscriptionManagerService extends ISub.Stub { builder.setDisplayName(nickName); builder.setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER); } - builder.setProfileClass(embeddedProfile.getProfileClass()); + + if (android.os.Build.isDebuggable() && + SystemProperties.getInt("telephony.test.bootstrap_cid", -2) + == carrierId) { + // Force set as provisioning profile for test purpose + log("Hardcording as bootstrap subscription for cid=" + carrierId); + builder.setProfileClass(SimInfo.PROFILE_CLASS_PROVISIONING); + } else { + builder.setProfileClass(embeddedProfile.getProfileClass()); + } builder.setPortIndex(getPortIndex(embeddedProfile.getIccid())); CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier(); @@ -1112,6 +1186,12 @@ public class SubscriptionManagerService extends ISub.Stub { String mnc = cid.getMnc(); builder.setMcc(mcc); builder.setMnc(mnc); + if (mFeatureFlags.oemEnabledSatelliteFlag()) { + builder.setOnlyNonTerrestrialNetwork( + isSatellitePlmn(mcc + mnc) ? 1 : 0); + } else { + log("updateEmbeddedSubscriptions: oemEnabledSatelliteFlag is disabled"); + } } // If cardId = unsupported or un-initialized, we have no reason to update DB. // Additionally, if the device does not support cardId for default eUICC, the @@ -1383,6 +1463,7 @@ public class SubscriptionManagerService extends ISub.Stub { MccTable.updateMccMncConfiguration(mContext, mccMnc); } setMccMnc(subId, mccMnc); + setNtn(subId, isSatellitePlmn(mccMnc)); } else { loge("updateSubscription: mcc/mnc is empty"); } @@ -1425,6 +1506,12 @@ public class SubscriptionManagerService extends ISub.Stub { loge("updateSubscription: ICC card is not available."); } + if (Flags.clearCachedImsPhoneNumberWhenDeviceLostImsRegistration()) { + // Clear the cached Ims phone number + // before proceeding with Ims Registration + setNumberFromIms(subId, new String("")); + } + // Attempt to restore SIM specific settings when SIM is loaded. Bundle result = mContext.getContentResolver().call( SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, @@ -1616,7 +1703,8 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Get all subscription info records from SIMs that are inserted now or previously inserted. + * Get all subscription info records from SIMs visible to the calling user that are inserted now + * or previously inserted. * * <p> * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission, @@ -1656,8 +1744,7 @@ public class SubscriptionManagerService extends ISub.Stub { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } - - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle()) // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full // list. Carrier apps can only get the subscriptions they have privileged. .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( @@ -1786,12 +1873,14 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted - * by {@link SubscriptionInfo#getSimSlotIndex} then by + * Get the SubscriptionInfo(s) of the active subscriptions for calling user. The records will be + * sorted by {@link SubscriptionInfo#getSimSlotIndex} then by * {@link SubscriptionInfo#getSubscriptionId}. * * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. + * @param isForAllProfiles whether the caller intends to see all subscriptions regardless + * association. * * @return Sorted list of the currently {@link SubscriptionInfo} records available on the * device. @@ -1804,13 +1893,13 @@ public class SubscriptionManagerService extends ISub.Stub { "carrier privileges", }) public List<SubscriptionInfo> getActiveSubscriptionInfoList(@NonNull String callingPackage, - @Nullable String callingFeatureId) { + @Nullable String callingFeatureId, boolean isForAllProfiles) { // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos // on the subs it has carrier privilege. if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, - "getAllSubInfoList")) { + "getActiveSubscriptionInfoList")) { // Ideally we should avoid silent failure, but since this API has already been used by // many apps and they do not expect the security exception, we return an empty list // here so it's consistent with pre-U behavior. @@ -1818,14 +1907,19 @@ public class SubscriptionManagerService extends ISub.Stub { + "permission. Returning empty list here."); return Collections.emptyList(); } - - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + if (isForAllProfiles && !hasAcrossAllUsersPermission()) { + //TODO(b/308809058 to determine whether the permission enforcement is needed) + loge("getActiveSubscriptionInfoList: " + + callingPackage + " has no appropriate permission."); + } + return getSubscriptionInfoStreamAsUser(isForAllProfiles + ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle()) .filter(SubscriptionInfoInternal::isActive) // Remove the identifier if the caller does not have sufficient permission. // carrier apps will get full subscription info on the subscriptions associated // to them. .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) + callingPackage, callingFeatureId, "getActiveSubscriptionInfoList")) .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) .thenComparing(SubscriptionInfo::getSubscriptionId)) .collect(Collectors.toList()); @@ -1836,6 +1930,8 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. + * @param isForAllProfiles whether the caller intends to see all subscriptions regardless + * association. * * @return the number of active subscriptions. * @@ -1848,20 +1944,27 @@ public class SubscriptionManagerService extends ISub.Stub { "carrier privileges", }) public int getActiveSubInfoCount(@NonNull String callingPackage, - @Nullable String callingFeatureId) { + @Nullable String callingFeatureId, boolean isForAllProfiles) { if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getAllSubInfoList")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + "carrier privilege"); } - - final long token = Binder.clearCallingIdentity(); - try { - return getActiveSubIdList(false).length; - } finally { - Binder.restoreCallingIdentity(token); + if (isForAllProfiles && !hasAcrossAllUsersPermission()) { + //TODO(b/308809058 to determine whether the permission enforcement is needed) + loge("getActiveSubInfoCount: " + + callingPackage + " has no appropriate permission."); } + return getActiveSubIdListAsUser(false, isForAllProfiles + ? UserHandle.ALL : BINDER_WRAPPER.getCallingUserHandle()).length; + } + + /**@return {@code true} if the caller is permitted to see all subscriptions. */ + private boolean hasAcrossAllUsersPermission() { + return hasPermissions(Manifest.permission.INTERACT_ACROSS_USERS, + Manifest.permission.INTERACT_ACROSS_USERS_FULL, + Manifest.permission.INTERACT_ACROSS_PROFILES); } /** @@ -1892,27 +1995,42 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable String callingFeatureId) { enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + return getAvailableSubscriptionsInternalStream() + .sorted(Comparator.comparing(SubscriptionInfoInternal::getSimSlotIndex) + .thenComparing(SubscriptionInfoInternal::getSubscriptionId)) + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .collect(Collectors.toList()); - // Now that all security checks pass, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if - // they are in inactive slot or programmatically disabled, they are still considered - // available. In this case we get their iccid from slot info and include their - // subscriptionInfos. - List<String> iccIds = getIccIdsOfInsertedPhysicalSims(); + } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId()) - || (mEuiccManager != null && mEuiccManager.isEnabled() - && subInfo.isEmbedded())) - .map(SubscriptionInfoInternal::toSubscriptionInfo) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - } finally { - Binder.restoreCallingIdentity(identity); - } + /** + * @return all the subscriptions visible to user on the device. + */ + private Stream<SubscriptionInfoInternal> getAvailableSubscriptionsInternalStream() { + // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if + // they are in inactive slot or programmatically disabled, they are still considered + // available. In this case we get their iccid from slot info and include their + // subscriptionInfos. + List<String> iccIds = getIccIdsOfInsertedPhysicalSims(); + + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId()) + || (mEuiccManager != null && mEuiccManager.isEnabled() + && subInfo.isEmbedded())); + } + + /** + * Tracks for each user Id, a list of subscriptions associated with it. + * A profile is barred from seeing unassociated subscriptions if it has its own subscription + * which is available to choose from the device. + */ + private void updateUserIdToAvailableSubs() { + mUserIdToAvailableSubs = getAvailableSubscriptionsInternalStream() + .collect(Collectors.groupingBy( + SubscriptionInfoInternal::getUserId, + Collectors.mapping(SubscriptionInfoInternal::getSubscriptionId, + Collectors.toList()))); + log("updateUserIdToAvailableSubs: " + mUserIdToAvailableSubs); } /** @@ -1947,8 +2065,7 @@ public class SubscriptionManagerService extends ISub.Stub { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + return getSubscriptionInfoStreamAsUser(BINDER_WRAPPER.getCallingUserHandle()) .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(subInfo -> subInfo.isEmbedded() && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) @@ -2739,10 +2856,39 @@ public class SubscriptionManagerService extends ISub.Stub { /** * @return The default subscription id. + * @deprecated Use {@link #getDefaultSubIdAsUser}. */ @Override public int getDefaultSubId() { - return mDefaultSubId.get(); + return getDefaultSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier()); + } + + /** + * @param userId The given user Id to check. + * @return The default subscription id. + */ + @Override + public int getDefaultSubIdAsUser(@UserIdInt int userId) { + return getDefaultAsUser(userId, mDefaultSubId.get()); + } + + /** + * Get the default subscription visible to the caller. + * @param userId The calling user Id. + * @param defaultValue Useful if the user owns more than one subscription. + * @return The subscription Id default to use. + */ + private int getDefaultAsUser(@UserIdInt int userId, int defaultValue) { + if (mFeatureFlags.workProfileApiSplit()) { + List<SubscriptionInfoInternal> subInfos = + getSubscriptionInfoStreamAsUser(UserHandle.of(userId)) + .filter(SubscriptionInfoInternal::isActive) + .toList(); + if (subInfos.size() == 1) { + return subInfos.get(0).getSubscriptionId(); + } + } + return defaultValue; } /** @@ -2834,10 +2980,20 @@ public class SubscriptionManagerService extends ISub.Stub { /** * @return The default subscription id for voice. + * @deprecated Use {@link #getDefaultVoiceSubIdAsUser}. */ @Override public int getDefaultVoiceSubId() { - return mDefaultVoiceSubId.get(); + return getDefaultVoiceSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier()); + } + + /** + * @param userId The calling user Id. + * @return The default voice subscription id. + */ + @Override + public int getDefaultVoiceSubIdAsUser(@UserIdInt int userId) { + return getDefaultAsUser(userId, mDefaultVoiceSubId.get()); } /** @@ -2880,10 +3036,24 @@ public class SubscriptionManagerService extends ISub.Stub { /** * @return The default subscription id for SMS. + * @deprecated Use {@link #getDefaultSmsSubIdAsUser}. */ @Override public int getDefaultSmsSubId() { - return mDefaultSmsSubId.get(); + return getDefaultSmsSubIdAsUser(BINDER_WRAPPER.getCallingUserHandle().getIdentifier()); + } + + /** + * Get the default sms subscription id associated with the user. When a subscription is + * associated with personal profile or work profile, the default sms subscription id will be + * always the subscription it is associated with. + * + * @param userId The given user Id to check. + * @return The default voice id. + */ + @Override + public int getDefaultSmsSubIdAsUser(@UserIdInt int userId) { + return getDefaultAsUser(userId, mDefaultSmsSubId.get()); } /** @@ -2940,19 +3110,30 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubIdList(boolean visibleOnly) { enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + // UserHandle.ALL because this API is exposed as system API. + return getActiveSubIdListAsUser(visibleOnly, UserHandle.ALL); + } - final long token = Binder.clearCallingIdentity(); - try { - return mSlotIndexToSubId.values().stream() - .filter(subId -> { - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId); - return subInfo != null && (!visibleOnly || subInfo.isVisible()); }) - .mapToInt(x -> x) - .toArray(); - } finally { - Binder.restoreCallingIdentity(token); - } + /** + * Get the active subscription id list as user. + * Must be used before clear Binder identity. + * + * @param visibleOnly {@code true} if only includes user visible subscription's sub id. + * @param user If {@code null}, uses the calling user handle to judge which subscriptions are + * accessible to the caller. + * @return List of the active subscription id. + */ + private int[] getActiveSubIdListAsUser(boolean visibleOnly, @NonNull final UserHandle user) { + return mSlotIndexToSubId.values().stream() + .filter(subId -> { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + return subInfo != null && (!visibleOnly || subInfo.isVisible()) + && isSubscriptionAssociatedWithUserInternal( + subInfo, user.getIdentifier()); + }) + .mapToInt(x -> x) + .toArray(); } /** @@ -3590,7 +3771,6 @@ public class SubscriptionManagerService extends ISub.Stub { } UserHandle userHandle = UserHandle.of(subInfo.getUserId()); - logv("getSubscriptionUserHandle subId = " + subId + " userHandle = " + userHandle); if (userHandle.getIdentifier() == UserHandle.USER_NULL) { return null; } @@ -3610,40 +3790,35 @@ public class SubscriptionManagerService extends ISub.Stub { * else {@code false} if subscription is not associated with user. * * @throws SecurityException if the caller doesn't have permissions required. - * + * @throws IllegalArgumentException if the subscription has no records on device. */ @Override public boolean isSubscriptionAssociatedWithUser(int subscriptionId, @NonNull UserHandle userHandle) { enforcePermissions("isSubscriptionAssociatedWithUser", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + SubscriptionInfoInternal subInfoInternal = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subscriptionId); + // Throw IAE if no record of the sub's association state. + if (subInfoInternal == null) { + throw new IllegalArgumentException( + "[isSubscriptionAssociatedWithUser]: Subscription doesn't exist: " + + subscriptionId); + } + + if (mFeatureFlags.workProfileApiSplit()) { + return isSubscriptionAssociatedWithUserInternal( + subInfoInternal, userHandle.getIdentifier()); + } long token = Binder.clearCallingIdentity(); try { - // Return true if there are no subscriptions on the device. - List<SubscriptionInfo> subInfoList = getAllSubInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (subInfoList == null || subInfoList.isEmpty()) { - return true; - } - - List<Integer> subIdList = subInfoList.stream().map(SubscriptionInfo::getSubscriptionId) - .collect(Collectors.toList()); - if (!subIdList.contains(subscriptionId)) { - // Return true as this subscription is not available on the device. - return true; - } - // Get list of subscriptions associated with this user. List<SubscriptionInfo> associatedSubscriptionsList = getSubscriptionInfoListAssociatedWithUser(userHandle); - if (associatedSubscriptionsList.isEmpty()) { - return false; - } - // Return true if required subscription is present in associated subscriptions list. for (SubscriptionInfo subInfo: associatedSubscriptionsList) { - if (subInfo.getSubscriptionId() == subscriptionId){ + if (subInfo.getSubscriptionId() == subscriptionId) { return true; } } @@ -3654,6 +3829,25 @@ public class SubscriptionManagerService extends ISub.Stub { } /** + * @param subInfo The subscription info to check. + * @param userId The caller user Id. + * @return {@code true} if the given user Id is allowed to access to the given subscription. + */ + private boolean isSubscriptionAssociatedWithUserInternal( + @NonNull SubscriptionInfoInternal subInfo, @UserIdInt int userId) { + if (!mFeatureFlags.workProfileApiSplit() + || !CompatChanges.isChangeEnabled(FILTER_ACCESSIBLE_SUBS_BY_USER, + Binder.getCallingUid())) { + return true; + } + return subInfo.getUserId() == userId + // Can access the unassociated sub if the user doesn't have its own. + || (subInfo.getUserId() == UserHandle.USER_NULL + && mUserIdToAvailableSubs.get(userId) == null) + || userId == UserHandle.USER_ALL; + } + + /** * Get list of subscriptions associated with user. * * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser @@ -3666,50 +3860,70 @@ public class SubscriptionManagerService extends ISub.Stub { * */ @Override - public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser( + @NonNull + public List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser( @NonNull UserHandle userHandle) { enforcePermissions("getSubscriptionInfoListAssociatedWithUser", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + if (mFeatureFlags.workProfileApiSplit()) { + return getSubscriptionInfoStreamAsUser(userHandle) + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .collect(Collectors.toList()); + } + long token = Binder.clearCallingIdentity(); try { - List<SubscriptionInfo> subInfoList = getAllSubInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (subInfoList == null || subInfoList.isEmpty()) { + List<SubscriptionInfoInternal> subInfoList = mSubscriptionDatabaseManager + .getAllSubscriptions(); + if (subInfoList.isEmpty()) { return new ArrayList<>(); } List<SubscriptionInfo> subscriptionsAssociatedWithUser = new ArrayList<>(); List<SubscriptionInfo> subscriptionsWithNoAssociation = new ArrayList<>(); - for (SubscriptionInfo subInfo : subInfoList) { - int subId = subInfo.getSubscriptionId(); - UserHandle subIdUserHandle = getSubscriptionUserHandle(subId); - if (userHandle.equals(subIdUserHandle)) { + for (SubscriptionInfoInternal subInfo : subInfoList) { + if (subInfo.getUserId() == userHandle.getIdentifier()) { // Store subscriptions whose user handle matches with required user handle. - subscriptionsAssociatedWithUser.add(subInfo); - } else if (subIdUserHandle == null) { + subscriptionsAssociatedWithUser.add(subInfo.toSubscriptionInfo()); + } else if (subInfo.getUserId() == UserHandle.USER_NULL) { // Store subscriptions whose user handle is set to null. - subscriptionsWithNoAssociation.add(subInfo); + subscriptionsWithNoAssociation.add(subInfo.toSubscriptionInfo()); } } UserManager userManager = mContext.getSystemService(UserManager.class); if ((userManager != null) && (userManager.isManagedProfile(userHandle.getIdentifier()))) { - // For work profile, return subscriptions associated only with work profile + // For work profile, return subscriptions associated only with work profile even + // if it's empty. return subscriptionsAssociatedWithUser; } - // For all other profiles, if subscriptionsAssociatedWithUser is empty return all the - // subscriptionsWithNoAssociation. - return subscriptionsAssociatedWithUser.isEmpty() ? - subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; + // For all other profiles, if subscriptionsAssociatedWithUser is empty return all + // the subscriptionsWithNoAssociation. + return subscriptionsAssociatedWithUser.isEmpty() + ? subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; } finally { Binder.restoreCallingIdentity(token); } } /** + * Get subscriptions accessible to the caller user. + * + * @param user The user to check. + * @return a stream of accessible internal subscriptions. + */ + @NonNull + private Stream<SubscriptionInfoInternal> getSubscriptionInfoStreamAsUser( + @NonNull final UserHandle user) { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(info -> isSubscriptionAssociatedWithUserInternal( + info, user.getIdentifier())); + } + + /** * Called during setup wizard restore flow to attempt to restore the backed up sim-specific * configs to device for all existing SIMs in the subscription database {@link SimInfo}. * Internally, it will store the backup data in an internal file. This file will persist on @@ -3776,14 +3990,26 @@ public class SubscriptionManagerService extends ISub.Stub { * @throws SecurityException if the caller does not have any permissions. */ private void enforcePermissions(@Nullable String message, @NonNull String ...permissions) { + if (!hasPermissions(permissions)) { + throw new SecurityException( + message + ". Does not have any of the following permissions. " + + Arrays.toString(permissions)); + } + } + + /** + * Check have any of the permissions + * @param permissions The permissions to check. + * @return {@code true} if the caller has one of the given permissions. + */ + private boolean hasPermissions(@NonNull String ...permissions) { for (String permission : permissions) { if (mContext.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) { - return; + return true; } } - throw new SecurityException(message + ". Does not have any of the following permissions. " - + Arrays.toString(permissions)); + return false; } /** @@ -3807,9 +4033,8 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Nullable public SubscriptionInfo getSubscriptionInfo(int subId) { - SubscriptionInfoInternal subscriptionInfoInternal = getSubscriptionInfoInternal(subId); - return subscriptionInfoInternal != null - ? subscriptionInfoInternal.toSubscriptionInfo() : null; + SubscriptionInfoInternal infoInternal = getSubscriptionInfoInternal(subId); + return infoInternal != null ? infoInternal.toSubscriptionInfo() : null; } /** @@ -3926,8 +4151,10 @@ public class SubscriptionManagerService extends ISub.Stub { */ @VisibleForTesting public void updateGroupDisabled() { - List<SubscriptionInfo> activeSubscriptions = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getFeatureId()); + List<SubscriptionInfoInternal> activeSubscriptions = mSubscriptionDatabaseManager + .getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + .collect(Collectors.toList()); for (SubscriptionInfo oppSubInfo : getOpportunisticSubscriptions( mContext.getOpPackageName(), mContext.getFeatureId())) { boolean groupDisabled = activeSubscriptions.stream() @@ -3949,6 +4176,39 @@ public class SubscriptionManagerService extends ISub.Stub { } /** + * @param mccMnc MccMnc value to check whether it supports non-terrestrial network or not. + * @return {@code true} if MCC/MNC is matched with in the device overlay key + * "config_satellite_esim_identifier", {@code false} otherwise. + */ + private boolean isSatellitePlmn(@NonNull String mccMnc) { + if (!mFeatureFlags.oemEnabledSatelliteFlag()) { + log("isSatellitePlmn: oemEnabledSatelliteFlag is disabled"); + return false; + } + + final int id = R.string.config_satellite_sim_identifier; + String overlayMccMnc = null; + try { + overlayMccMnc = mContext.getResources().getString(id); + } catch (Resources.NotFoundException ex) { + loge("isSatellitePlmn: id= " + id + ", ex=" + ex); + } + if (TextUtils.isEmpty(overlayMccMnc) && isMockModemAllowed()) { + log("isSatellitePlmn: Read config_satellite_sim_identifier from device config"); + overlayMccMnc = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, + "config_satellite_sim_identifier", ""); + } + log("isSatellitePlmn: overlayMccMnc=" + overlayMccMnc + ", mccMnc=" + mccMnc); + return TextUtils.equals(mccMnc, overlayMccMnc); + } + + private boolean isMockModemAllowed() { + boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false); + return (SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false) + || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false)); + } + + /** * Log debug messages. * * @param s debug messages @@ -3977,15 +4237,6 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Log verbose messages. - * - * @param s verbose messages - */ - private void logv(@NonNull String s) { - Rlog.v(LOG_TAG, s); - } - - /** * Dump the state of {@link SubscriptionManagerService}. * * @param fd File descriptor @@ -4019,6 +4270,7 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("activeDataSubId=" + getActiveDataSubscriptionId()); pw.println("defaultSmsSubId=" + getDefaultSmsSubId()); pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded()); + pw.println("mUserIdToAvailableSubs=" + mUserIdToAvailableSubs); pw.println(); for (int i = 0; i < mSimState.length; i++) { pw.println("mSimState[" + i + "]=" diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 9456467355..0459bf676e 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -597,17 +597,17 @@ public class UiccController extends Handler { log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling " + "getIccCardStatus"); } - mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, - phoneId)); // slot status should be the same on all RILs; request it only for phoneId 0 if (phoneId == 0) { if (DBG) { log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, " - + "calling getIccSlotsStatus"); + + "calling getSimSlotsStatus"); } mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE, phoneId)); } + mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, + phoneId)); break; case EVENT_GET_ICC_STATUS_DONE: if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); @@ -997,6 +997,12 @@ public class UiccController extends Handler { return; } + if (!SubscriptionManager.isValidPhoneId(phoneId)) { + Rlog.e(LOG_TAG, "updateSimState: Cannot update carrier services. " + + "Invalid phone id " + phoneId); + return; + } + // At this point, the SIM state must be a final state (meaning we won't // get more SIM state updates). So resolve the carrier id and update the // carrier services. @@ -1039,11 +1045,6 @@ public class UiccController extends Handler { slotId = index; } - if (!mCis[0].supportsEid()) { - // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID - if (DBG) log("eid is not supported"); - mDefaultEuiccCardId = UNSUPPORTED_CARD_ID; - } mPhoneIdToSlotId[index] = slotId; if (VDBG) logPhoneIdToSlotIdMapping(); diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp index 9fb4fe642d..51ab6173dd 100644 --- a/tests/telephonytests/Android.bp +++ b/tests/telephonytests/Android.bp @@ -41,6 +41,7 @@ android_test { "truth", "testables", "platform-compat-test-rules", + "flag-junit", ], jarjar_rules: ":jarjar-rules-telephony-tests", diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java index 80167d6ece..2df688d5ab 100644 --- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java +++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java @@ -48,7 +48,7 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class ImsFeatureTest { // Public for Mockito testing - public class CapabilityCallback extends IImsCapabilityCallback.Stub { + public static class CapabilityCallback extends IImsCapabilityCallback.Stub { @Override public void onQueryCapabilityConfiguration(int capability, int radioTech, boolean enabled) diff --git a/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java b/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java index 337e296629..df533744c9 100644 --- a/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java +++ b/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java @@ -41,7 +41,7 @@ public class ImsMmTelManagerTests extends TelephonyTest { ITelephony mMockTelephonyInterface; BinderCacheManager<ITelephony> mBinderCache; - public class LocalCallback extends ImsMmTelManager.RegistrationCallback { + public static class LocalCallback extends ImsMmTelManager.RegistrationCallback { int mRegResult = -1; @Override diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java index 9fd89ffcb1..e23a7f2cba 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java @@ -41,12 +41,15 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Pair; +import com.android.internal.telephony.flags.FeatureFlags; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; import java.security.PublicKey; import java.text.SimpleDateFormat; @@ -87,7 +90,7 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { + "\"public-key\": \"" + CERT + "\"}]}"; private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; - + private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { logd("CarrierActionAgentTest +Setup!"); @@ -98,7 +101,8 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { // Capture listener to emulate the carrier config change notification used later ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); - mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone); + mFeatureFlags = Mockito.mock(FeatureFlags.class); + mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone, mFeatureFlags); verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java index dfb91a52b1..73450229e3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static com.android.internal.telephony.CarrierServiceStateTracker.ACTION_NEVER_ASK_AGAIN; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; @@ -26,12 +28,15 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.isA; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationManager; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -78,11 +83,12 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { mBundle = mContextFixture.getCarrierConfigBundle(); when(mPhone.getSubId()).thenReturn(SUB_ID); when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_WATCH); // Capture listener to emulate the carrier config change notification used later ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); - mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST); + mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST, mFeatureFlags); verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); @@ -271,4 +277,54 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { verify(mNotificationManager, never()).cancel( CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG, SUB_ID); } + + /** + * Verify the WIFI emergency calling notification is silenced if the user requests (via a + * simulated notification action) + */ + @Test + @SmallTest + public void testEmergencyNotificationBehaviorWhenSilenced() { + when(mFeatureFlags.stopSpammingEmergencyNotification()).thenReturn(true); + logd(LOG_TAG + ":testEmergencyNotificationBehaviorWhenSilenced()"); + sendMessageOnHandler(CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK); + + // verify the notification was sent + verify(mNotificationManager, times(1)).notify( + eq(CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG), + eq(SUB_ID), isA(Notification.class)); + + // simulate the user clicking the "Do Not Show Again" button on the notification + mCarrierSST.mActionReceiver.onReceive(mContext, new Intent(ACTION_NEVER_ASK_AGAIN)); + + // resend the msg to trigger the notification to be posted + sendMessageOnHandler(CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK); + + // verify the notification was sent + verify(mNotificationManager, times(1)).notify( + eq(CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG), + eq(SUB_ID), isA(Notification.class)); + } + + + /** Verifies notification map is empty when device is watch. */ + @Test + @SmallTest + public void testNotificationMapWhenDeviceIsWatch() { + doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_WATCH); + + CarrierServiceStateTracker tracker = new CarrierServiceStateTracker(mPhone, mSST, + mFeatureFlags); + + assertTrue(tracker.getNotificationTypeMap().isEmpty()); + } + + private void sendMessageOnHandler(int messageWhat) { + Message notificationMsg = mSpyCarrierSST.obtainMessage(messageWhat, null); + doReturn(true).when(mSpyCarrierSST).evaluateSendingMessage(any()); + doReturn(0).when(mSpyCarrierSST).getDelay(any()); + doReturn(mNotificationManager).when(mSpyCarrierSST).getNotificationManager(any()); + mSpyCarrierSST.handleMessage(notificationMsg); + processAllMessages(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java index 40be490587..722f6ac985 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java @@ -42,6 +42,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import org.junit.After; @@ -49,6 +50,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; @@ -60,13 +63,16 @@ public final class CellBroadcastConfigTrackerTest extends TelephonyTest { private CommandsInterface mSpyCi; private CellBroadcastConfigTracker mTracker; + @Mock private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mFeatureFlags = Mockito.mock(FeatureFlags.class); mSpyCi = spy(mSimulatedCommands); mPhone = new GsmCdmaPhone(mContext, mSpyCi, mNotifier, true, 0, - PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); + PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager, + mFeatureFlags); mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone, true); mPhone.mCellBroadcastConfigTracker = mTracker; processAllMessages(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java index 8cd5dc3630..85ea85565e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java @@ -39,6 +39,7 @@ import android.telephony.NetworkService; import android.telephony.NetworkServiceCallback; import android.telephony.NrVopsSupportInfo; import android.telephony.ServiceState; +import android.telephony.SmsManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.VopsSupportInfo; @@ -92,6 +93,9 @@ public class CellularNetworkServiceTest extends TelephonyTest { int dds = SubscriptionManager.getDefaultDataSubscriptionId(); doReturn(dds).when(mPhone).getSubId(); + mContextFixture.getCarrierConfigBundle().putBoolean( + SmsManager.MMS_CONFIG_MMS_ENABLED, false); + logd("CellularNetworkServiceTest -Setup!"); } @@ -510,4 +514,48 @@ public class CellularNetworkServiceTest extends TelephonyTest { new CellIdentityWcdma(), mPhone.getCarrierId())); } + + @Test + public void testGetAvailableServices_withMmsEnabled() { + mContextFixture.getCarrierConfigBundle().putBoolean( + SmsManager.MMS_CONFIG_MMS_ENABLED, true); + + VopsSupportInfo lteVopsSupportInfo = + new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, + LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE); + int voiceRegState = NetworkRegistrationInfo.REGISTRATION_STATE_HOME; + int voiceRadioTech = ServiceState.RIL_RADIO_TECHNOLOGY_UMTS; + int reasonForDenial = 0; + int maxDataCalls = 4; + + mSimulatedCommands.setVoiceRegState(voiceRegState); + mSimulatedCommands.setVoiceRadioTech(voiceRadioTech); + mSimulatedCommands.mReasonForDenial = reasonForDenial; + mSimulatedCommands.mMaxDataCalls = maxDataCalls; + mSimulatedCommands.notifyNetworkStateChanged(); + + int domain = NetworkRegistrationInfo.DOMAIN_PS; + List<Integer> availableServices = Arrays.asList( + NetworkRegistrationInfo.SERVICE_TYPE_DATA, + NetworkRegistrationInfo.SERVICE_TYPE_MMS); + try { + mBinder.requestNetworkRegistrationInfo(0, domain, mCallback); + } catch (RemoteException e) { + assertTrue(false); + } + + NetworkRegistrationInfo expectedState = new NetworkRegistrationInfo( + domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, voiceRegState, + ServiceState.rilRadioTechnologyToNetworkType(voiceRadioTech), reasonForDenial, + false, availableServices, null, "", maxDataCalls, + false, false, false, lteVopsSupportInfo); + + try { + verify(mCallback, timeout(1000).times(1)) + .onRequestNetworkRegistrationInfoComplete( + eq(NetworkServiceCallback.RESULT_SUCCESS), eq(expectedState)); + } catch (RemoteException e) { + assertTrue(false); + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index ea19b62625..da3920e872 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -108,7 +108,7 @@ import java.util.Set; * Controls a test {@link Context} as would be provided by the Android framework to an * {@code Activity}, {@code Service} or other system-instantiated component. * - * Contains Fake<Component> classes like FakeContext for components that require complex and + * Contains {@code Fake<Component>} classes like FakeContext for components that require complex and * reusable stubbing. Others can be mocked using Mockito functions in tests or constructor/public * methods of this class. */ @@ -117,7 +117,6 @@ public class ContextFixture implements TestFixture<Context> { public static final String PERMISSION_ENABLE_ALL = "android.permission.STUB_PERMISSION"; public static class FakeContentProvider extends MockContentProvider { - private String[] mColumns = {"name", "value"}; private HashMap<String, String> mKeyValuePairs = new HashMap<String, String>(); private int mNumKeyValuePairs = 0; private HashMap<String, String> mFlags = new HashMap<>(); @@ -747,18 +746,14 @@ public class ContextFixture implements TestFixture<Context> { doAnswer(new Answer<List<ResolveInfo>>() { @Override public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { - return doQueryIntentServices( - (Intent) invocation.getArguments()[0], - (Integer) invocation.getArguments()[1]); + return doQueryIntentServices((Intent) invocation.getArguments()[0]); } }).when(mPackageManager).queryIntentServices((Intent) any(), anyInt()); doAnswer(new Answer<List<ResolveInfo>>() { @Override public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable { - return doQueryIntentServices( - (Intent) invocation.getArguments()[0], - (Integer) invocation.getArguments()[1]); + return doQueryIntentServices((Intent) invocation.getArguments()[0]); } }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), any()); @@ -766,6 +761,7 @@ public class ContextFixture implements TestFixture<Context> { doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(nullable(String.class), anyInt()); } catch (NameNotFoundException e) { + Log.d(TAG, "NameNotFoundException: e=" + e); } doAnswer((Answer<Boolean>) @@ -775,7 +771,7 @@ public class ContextFixture implements TestFixture<Context> { try { doReturn(mResources).when(mPackageManager).getResourcesForApplication(anyString()); } catch (NameNotFoundException ex) { - Log.d(TAG, "NameNotFoundException: " + ex); + Log.d(TAG, "NameNotFoundException: ex=" + ex); } doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); @@ -851,7 +847,7 @@ public class ContextFixture implements TestFixture<Context> { mMockBindingFailureForPackage.add(packageName); } - private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { + private List<ResolveInfo> doQueryIntentServices(Intent intent) { List<ResolveInfo> result = new ArrayList<ResolveInfo>(); for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { ResolveInfo resolveInfo = new ResolveInfo(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java index 2f4182a993..f7f67a5ac1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.telephony.CellIdentityGsm; import android.telephony.CellInfo; @@ -34,12 +35,14 @@ import android.telephony.TelephonyManager; import android.telephony.ims.ImsCallProfile; import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhoneCall; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import java.util.ArrayList; import java.util.Collections; @@ -51,6 +54,8 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { private DefaultPhoneNotifier mDefaultPhoneNotifierUT; + private FeatureFlags mFeatureFlags; + // Mocked classes SignalStrength mSignalStrength; CellInfo mCellInfo; @@ -66,13 +71,14 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mSignalStrength = mock(SignalStrength.class); mCellInfo = mock(CellInfo.class); + mFeatureFlags = Mockito.mock(FeatureFlags.class); mForeGroundCall = mock(GsmCdmaCall.class); mBackGroundCall = mock(GsmCdmaCall.class); mRingingCall = mock(GsmCdmaCall.class); mImsForeGroundCall = mock(ImsPhoneCall.class); mImsBackGroundCall = mock(ImsPhoneCall.class); mImsRingingCall = mock(ImsPhoneCall.class); - mDefaultPhoneNotifierUT = new DefaultPhoneNotifier(mContext); + mDefaultPhoneNotifierUT = new DefaultPhoneNotifier(mContext, mFeatureFlags); } @After @@ -94,6 +100,7 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { @Test @SmallTest public void testNotifyDataActivity() throws Exception { + when(mFeatureFlags.notifyDataActivityChangedWithSlot()).thenReturn(false); //mock data activity state doReturn(TelephonyManager.DATA_ACTIVITY_NONE).when(mPhone).getDataActivityState(); mDefaultPhoneNotifierUT.notifyDataActivity(mPhone); @@ -106,6 +113,36 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { verify(mTelephonyRegistryManager).notifyDataActivityChanged(eq(1), eq(TelephonyManager.DATA_ACTIVITY_IN)); } + @Test @SmallTest + public void testNotifyDataActivityWithSlot() throws Exception { + when(mFeatureFlags.notifyDataActivityChangedWithSlot()).thenReturn(true); + //mock data activity state + doReturn(TelephonyManager.DATA_ACTIVITY_NONE).when(mPhone).getDataActivityState(); + doReturn(PHONE_ID).when(mPhone).getPhoneId(); + mDefaultPhoneNotifierUT.notifyDataActivity(mPhone); + verify(mTelephonyRegistryManager).notifyDataActivityChanged(eq(1), eq(0), + eq(TelephonyManager.DATA_ACTIVITY_NONE)); + + doReturn(1/*subId*/).when(mPhone).getSubId(); + doReturn(TelephonyManager.DATA_ACTIVITY_IN).when(mPhone).getDataActivityState(); + mDefaultPhoneNotifierUT.notifyDataActivity(mPhone); + verify(mTelephonyRegistryManager).notifyDataActivityChanged(eq(1), eq(1), + eq(TelephonyManager.DATA_ACTIVITY_IN)); + + doReturn(SUB_ID).when(mPhone).getSubId(); + doReturn(TelephonyManager.DATA_ACTIVITY_NONE).when(mPhone).getDataActivityState(); + doReturn(2/*phoneId*/).when(mPhone).getPhoneId(); + mDefaultPhoneNotifierUT.notifyDataActivity(mPhone); + verify(mTelephonyRegistryManager).notifyDataActivityChanged(eq(2), eq(0), + eq(TelephonyManager.DATA_ACTIVITY_NONE)); + + doReturn(1/*subId*/).when(mPhone).getSubId(); + doReturn(TelephonyManager.DATA_ACTIVITY_INOUT).when(mPhone).getDataActivityState(); + mDefaultPhoneNotifierUT.notifyDataActivity(mPhone); + verify(mTelephonyRegistryManager).notifyDataActivityChanged( + eq(2), eq(1), eq(TelephonyManager.DATA_ACTIVITY_INOUT)); + + } @Test @SmallTest public void testNotifySignalStrength() throws Exception { diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java index 28a37f7f40..018759ac89 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java @@ -20,7 +20,9 @@ import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED; import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -30,6 +32,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static java.util.Arrays.asList; @@ -40,22 +43,31 @@ import android.content.Intent; import android.hardware.radio.V1_5.IndicationFilter; import android.net.ConnectivityManager; import android.net.TetheringManager; +import android.os.AsyncResult; import android.os.BatteryManager; +import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.test.suitebuilder.annotation.MediumTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.flags.FeatureFlags; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -114,6 +126,7 @@ public class DeviceStateMonitorTest extends TelephonyTest { private static final int STATE_OFF = 0; private static final int STATE_ON = 1; + private static final long TIMEOUT = 500; // The keys are the single IndicationFilter flags, // The values are the array of states, when one state turn on, the corresponding @@ -135,6 +148,9 @@ public class DeviceStateMonitorTest extends TelephonyTest { UiModeManager mUiModeManager; private DeviceStateMonitor mDSM; + private TestSatelliteController mSatelliteControllerUT; + + @Mock private FeatureFlags mFeatureFlags; // Given a stateType, return the event type that can change the state private int state2Event(@StateType int stateType) { @@ -162,11 +178,12 @@ public class DeviceStateMonitorTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); mUiModeManager = mock(UiModeManager.class); mContextFixture.setSystemService(Context.UI_MODE_SERVICE, mUiModeManager); // We don't even need a mock executor, we just need to not throw. doReturn(null).when(mContextFixture.getTestDouble()).getMainExecutor(); - mDSM = new DeviceStateMonitor(mPhone); + mDSM = new DeviceStateMonitor(mPhone, mFeatureFlags); // Initialize with ALL states off updateAllStatesToOff(); @@ -177,6 +194,7 @@ public class DeviceStateMonitorTest extends TelephonyTest { @After public void tearDown() throws Exception { + mSatelliteControllerUT = null; mDSM = null; super.tearDown(); } @@ -453,4 +471,160 @@ public class DeviceStateMonitorTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).setUnsolResponseFilter( eq(INDICATION_FILTERS_MINIMUM), nullable(Message.class)); } + + @Test + public void testRegisterForSignalStrengthReportDecisionWithFeatureEnabled() { + logd("testRegisterForSignalStrengthReportDecisionWithFeatureEnabled()"); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + mSatelliteControllerUT = new TestSatelliteController(Looper.myLooper(), mDSM); + + updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0); + updateState(STATE_TYPE_SCREEN, STATE_OFF); + mSatelliteControllerUT.resetCount(); + sEventDeviceStatusChanged.drainPermits(); + + updateState(STATE_TYPE_SCREEN, STATE_ON); + assertTrue(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(1, mSatelliteControllerUT.getStopEventCount()); + mSatelliteControllerUT.resetCount(); + + mSatelliteControllerUT.resetCount(); + updateState(STATE_TYPE_SCREEN, STATE_OFF); + assertTrue(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(1, mSatelliteControllerUT.getStopEventCount()); + mSatelliteControllerUT.resetCount(); + + updateState(STATE_TYPE_RADIO_ON, 0); + assertTrue(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(1, mSatelliteControllerUT.getStopEventCount()); + mSatelliteControllerUT.resetCount(); + + updateState(STATE_TYPE_SCREEN, STATE_ON); + assertTrue(waitForEventDeviceStatusChanged()); + assertEquals(1, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + mSatelliteControllerUT.resetCount(); + + updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0); + assertTrue(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(1, mSatelliteControllerUT.getStopEventCount()); + } + + @Test + public void testRegisterForSignalStrengthReportDecisionWithFeatureDisabled() { + logd("testRegisterForSignalStrengthReportDecisionWithFeatureDisabled()"); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + mSatelliteControllerUT = new TestSatelliteController(Looper.myLooper(), mDSM); + + updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0); + updateState(STATE_TYPE_SCREEN, STATE_OFF); + mSatelliteControllerUT.resetCount(); + sEventDeviceStatusChanged.drainPermits(); + + + /* Sending stop ntn signal strength as radio is off */ + updateState(STATE_TYPE_SCREEN, STATE_ON); + assertFalse(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + + updateState(STATE_TYPE_SCREEN, STATE_OFF); + assertFalse(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + + updateState(STATE_TYPE_RADIO_ON, 0); + assertFalse(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + + updateState(STATE_TYPE_SCREEN, STATE_ON); + assertFalse(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + + updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0); + assertFalse(waitForEventDeviceStatusChanged()); + assertEquals(0, mSatelliteControllerUT.getStartEventCount()); + assertEquals(0, mSatelliteControllerUT.getStopEventCount()); + } + + private static Semaphore sEventDeviceStatusChanged = new Semaphore(0); + private boolean waitForEventDeviceStatusChanged() { + try { + if (!sEventDeviceStatusChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + logd("Time out to receive EVENT_DEVICE_STATUS_CHANGED"); + return false; + } + } catch (Exception ex) { + logd("waitForEventDeviceStatusChanged: ex=" + ex); + return false; + } + return true; + } + + private static class TestSatelliteController extends Handler { + public static final int EVENT_DEVICE_STATUS_CHANGED = 35; + private final DeviceStateMonitor mDsm; + private int mStartEventCount; + private int mStopEventCount; + + TestSatelliteController(Looper looper, DeviceStateMonitor dsm) { + super(looper); + mDsm = dsm; + mDsm.registerForSignalStrengthReportDecision(this, EVENT_DEVICE_STATUS_CHANGED, null); + } + + /** + * Resets the count of occurred events. + */ + public void resetCount() { + mStartEventCount = 0; + mStopEventCount = 0; + } + + public int getStartEventCount() { + return mStartEventCount; + } + + public int getStopEventCount() { + return mStopEventCount; + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_DEVICE_STATUS_CHANGED: { + logd("EVENT_DEVICE_STATUS_CHANGED"); + AsyncResult ar = (AsyncResult) msg.obj; + boolean shouldReport = (boolean) ar.result; + if (shouldReport) { + startSendingNtnSignalStrength(); + } else { + stopSendingNtnSignalStrength(); + } + try { + sEventDeviceStatusChanged.release(); + } catch (Exception ex) { + logd("waitForEventDeviceStatusChanged: ex=" + ex); + } + break; + } + default: + break; + } + } + + private void startSendingNtnSignalStrength() { + mStartEventCount++; + } + + private void stopSendingNtnSignalStrength() { + mStopEventCount++; + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java index f729b800cd..8eb2de6d4e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java @@ -42,11 +42,14 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.text.TextUtils; +import com.android.internal.telephony.flags.FeatureFlags; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import java.util.Collections; import java.util.concurrent.Executor; @@ -54,17 +57,18 @@ import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class DisplayInfoControllerTest extends TelephonyTest { - private static final int PHONE_ID = 0; private static final String MCC = "600"; private static final String MNC = "01"; private static final String NUMERIC = MCC + MNC; private static final String NETWORK = "TestNet"; + // Mocked classes + private FeatureFlags mFeatureFlags; + private DisplayInfoController mDic; private ServiceStateTracker mSst; private ServiceStateTrackerTestHandler mSstHandler; - private SignalStrengthController mSsc; private PersistableBundle mBundle; private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @@ -75,8 +79,8 @@ public class DisplayInfoControllerTest extends TelephonyTest { @Override public void onLooperPrepared() { - mSsc = new SignalStrengthController(mPhone); - doReturn(mSsc).when(mPhone).getSignalStrengthController(); + SignalStrengthController ssc = new SignalStrengthController(mPhone); + doReturn(ssc).when(mPhone).getSignalStrengthController(); doReturn(new ServiceState()).when(mPhone).getServiceState(); doReturn(NUMERIC).when(mTelephonyManager).getSimOperatorNumericForPhone(eq(PHONE_ID)); doReturn(NETWORK).when(mTelephonyManager).getSimOperatorNameForPhone(eq(PHONE_ID)); @@ -87,7 +91,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass( CarrierConfigManager.CarrierConfigChangeListener.class); - mSst = new ServiceStateTracker(mPhone, mSimulatedCommands); + mSst = new ServiceStateTracker(mPhone, mSimulatedCommands, mFeatureFlags); verify(mCarrierConfigManager, atLeast(2)).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(1); @@ -101,6 +105,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { logd("DisplayInfoControllerTest setup!"); super.setUp(getClass().getSimpleName()); + mFeatureFlags = Mockito.mock(FeatureFlags.class); doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mBundle = mContextFixture.getCarrierConfigBundle(); mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); @@ -191,7 +196,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { assertFalse(ss.getRoaming()); // home doReturn(mSst).when(mPhone).getServiceStateTracker(); - mDic = new DisplayInfoController(mPhone); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); mDic.updateTelephonyDisplayInfo(); TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); @@ -211,7 +216,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { assertFalse(ss.getRoaming()); // home doReturn(mSst).when(mPhone).getServiceStateTracker(); - mDic = new DisplayInfoController(mPhone); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); mDic.updateTelephonyDisplayInfo(); TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); @@ -232,7 +237,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { assertTrue(ss1.getRoaming()); // roam doReturn(mSst).when(mPhone).getServiceStateTracker(); - mDic = new DisplayInfoController(mPhone); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); mDic.updateTelephonyDisplayInfo(); TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); @@ -254,7 +259,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { assertFalse(ss.getRoaming()); // home doReturn(mSst).when(mPhone).getServiceStateTracker(); - mDic = new DisplayInfoController(mPhone); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); mDic.updateTelephonyDisplayInfo(); TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); @@ -275,10 +280,32 @@ public class DisplayInfoControllerTest extends TelephonyTest { assertTrue(ss1.getRoaming()); // roam doReturn(mSst).when(mPhone).getServiceStateTracker(); - mDic = new DisplayInfoController(mPhone); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); mDic.updateTelephonyDisplayInfo(); TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); assertTrue(tdi.isRoaming()); } + + @Test + public void testIsRoamingOverride_HideRoamingIndicator() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + mBundle.putStringArray( + CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC}); + mBundle.putBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL, false); + doReturn(true).when(mFeatureFlags).hideRoamingIcon(); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + ServiceState ss1 = mSst.getServiceState(); + + assertTrue(ss1.getRoaming()); // roam + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone, mFeatureFlags); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertFalse(tdi.isRoaming()); // display override + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index 3be850924c..26920577b5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -127,7 +127,11 @@ public class FakeTelephonyProvider extends MockContentProvider { + "," + Telephony.SimInfo.COLUMN_TP_MESSAGE_REF + " INTEGER DEFAULT -1," + Telephony.SimInfo.COLUMN_USER_HANDLE + " INTEGER DEFAULT " - + UserHandle.USER_NULL + + UserHandle.USER_NULL + "," + + Telephony.SimInfo.COLUMN_SATELLITE_ENABLED + " INTEGER DEFAULT 0," + + Telephony.SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER + + " INTEGER DEFAULT 0, " + + Telephony.SimInfo.COLUMN_IS_NTN + " INTEGER DEFAULT 0" + ");"; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java index 2fdff9ed7b..369980c4e4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java @@ -41,7 +41,6 @@ import android.testing.TestableLooper; import androidx.test.filters.FlakyTest; import com.android.internal.telephony.PhoneInternalInterface.DialArgs; -import com.android.internal.telephony.domainselection.DomainSelectionResolver; import org.junit.After; import org.junit.Assert; @@ -67,16 +66,12 @@ public class GsmCdmaCallTrackerTest extends TelephonyTest { // Mocked classes private GsmCdmaConnection mConnection; private Handler mHandler; - private DomainSelectionResolver mDomainSelectionResolver; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mConnection = mock(GsmCdmaConnection.class); mHandler = mock(Handler.class); - mDomainSelectionResolver = mock(DomainSelectionResolver.class); - doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); - DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); mSimulatedCommands.setRadioPower(true, null); mPhone.mCi = this.mSimulatedCommands; @@ -91,7 +86,6 @@ public class GsmCdmaCallTrackerTest extends TelephonyTest { @After public void tearDown() throws Exception { mCTUT = null; - DomainSelectionResolver.setDomainSelectionResolver(null); super.tearDown(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 465880aa7d..935da5ac7b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -21,6 +21,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_IMS_DEREGISTRATION_TRIGGERED; import static com.android.internal.telephony.Phone.EVENT_RADIO_AVAILABLE; +import static com.android.internal.telephony.Phone.EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE; import static com.android.internal.telephony.Phone.EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; @@ -72,6 +73,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.CellIdentity; import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; import android.telephony.RadioAccessFamily; @@ -89,6 +91,7 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -113,6 +116,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.InOrder; +import org.mockito.Mock; import org.mockito.Mockito; import java.util.ArrayList; @@ -129,7 +133,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private UiccSlot mUiccSlot; private CommandsInterface mMockCi; private AdnRecordCache adnRecordCache; - private DomainSelectionResolver mDomainSelectionResolver; //mPhoneUnderTest private GsmCdmaPhone mPhoneUT; @@ -138,6 +141,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // app is not currently debuggable. For now, we use the real device config and ensure that // we reset the cellular_security namespace property to its pre-test value after every test. private DeviceConfig.Properties mPreTestProperties; + @Mock private FeatureFlags mFeatureFlags; private static final int EVENT_EMERGENCY_CALLBACK_MODE_EXIT = 1; private static final int EVENT_EMERGENCY_CALL_TOGGLE = 2; @@ -169,14 +173,14 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mUiccPort = Mockito.mock(UiccPort.class); mMockCi = Mockito.mock(CommandsInterface.class); adnRecordCache = Mockito.mock(AdnRecordCache.class); - mDomainSelectionResolver = Mockito.mock(DomainSelectionResolver.class); + mFeatureFlags = Mockito.mock(FeatureFlags.class); + doReturn(false).when(mSST).isDeviceShuttingDown(); doReturn(true).when(mImsManager).isVolteEnabledByPlatform(); - doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); - DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); mPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0, - PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); + PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager, + mFeatureFlags); mPhoneUT.setVoiceCallSessionStats(mVoiceCallSessionStats); ArgumentCaptor<Integer> integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class); verify(mUiccController).registerForIccChanged(eq(mPhoneUT), integerArgumentCaptor.capture(), @@ -191,7 +195,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void tearDown() throws Exception { mPhoneUT.removeCallbacksAndMessages(null); mPhoneUT = null; - DomainSelectionResolver.setDomainSelectionResolver(null); try { DeviceConfig.setProperties(mPreTestProperties); } catch (DeviceConfig.BadConfigException e) { @@ -981,9 +984,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).getBasebandVersion(nullable(Message.class)); verify(mSimulatedCommandsVerifier).getDeviceIdentity(nullable(Message.class)); verify(mSimulatedCommandsVerifier).getRadioCapability(nullable(Message.class)); - // once as part of constructor, and once on radio available - verify(mSimulatedCommandsVerifier, times(2)).startLceService(anyInt(), anyBoolean(), - nullable(Message.class)); // EVENT_RADIO_ON verify(mSimulatedCommandsVerifier).getVoiceRadioTechnology(nullable(Message.class)); @@ -1006,8 +1006,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // EVENT_RADIO_AVAILABLE verify(mSimulatedCommandsVerifier, times(2)).getBasebandVersion(nullable(Message.class)); verify(mSimulatedCommandsVerifier, times(2)).getDeviceIdentity(nullable(Message.class)); - verify(mSimulatedCommandsVerifier, times(3)).startLceService(anyInt(), anyBoolean(), - nullable(Message.class)); // EVENT_RADIO_ON verify(mSimulatedCommandsVerifier, times(2)).getVoiceRadioTechnology( @@ -1040,7 +1038,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { }; Phone phone = new GsmCdmaPhone(mContext, sc, mNotifier, true, 0, - PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); + PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager, + mFeatureFlags); phone.setVoiceCallSessionStats(mVoiceCallSessionStats); ArgumentCaptor<Integer> integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class); verify(mUiccController).registerForIccChanged(eq(phone), integerArgumentCaptor.capture(), @@ -1482,6 +1481,143 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(captor.getValue().what, Phone.EVENT_GET_RADIO_CAPABILITY); } + @Test + public void testNrCapabilityChanged_firstRequest_noChangeNeeded() { + when(mFeatureFlags.enableCarrierConfigN1Control()).thenReturn(true); + + mPhoneUT.mCi = mMockCi; + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + new int[]{ + CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, + CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA}); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(Phone.EVENT_CARRIER_CONFIG_CHANGED)); + processAllMessages(); + + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mMockCi, times(1)).isN1ModeEnabled(messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), Boolean.TRUE, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + + verify(mMockCi, never()).setN1ModeEnabled(anyBoolean(), any()); + } + + @Test + public void testNrCapabilityChanged_firstRequest_needsChange() { + when(mFeatureFlags.enableCarrierConfigN1Control()).thenReturn(true); + + mPhoneUT.mCi = mMockCi; + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + new int[]{ + CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, + CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA}); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(Phone.EVENT_CARRIER_CONFIG_CHANGED)); + processAllMessages(); + + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mMockCi, times(1)).isN1ModeEnabled(messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), Boolean.FALSE, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + + verify(mMockCi, times(1)).setN1ModeEnabled(eq(true), messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), Boolean.TRUE, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + } + + @Test + public void testNrCapabilityChanged_CarrierConfigChanges() { + when(mFeatureFlags.enableCarrierConfigN1Control()).thenReturn(true); + + // Initialize the inner cache and set the modem to N1 mode = enabled/true + testNrCapabilityChanged_firstRequest_needsChange(); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + // Remove SA support and send an additional carrier config change + bundle.putIntArray( + CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + new int[]{CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA}); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(Phone.EVENT_CARRIER_CONFIG_CHANGED)); + processAllMessages(); + + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mMockCi, times(1)).isN1ModeEnabled(any()); // not called again + verify(mMockCi, times(1)).setN1ModeEnabled(eq(false), messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), null, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + } + + @Test + public void testNrCapabilityChanged_CarrierConfigChanges_ErrorResponse() { + when(mFeatureFlags.enableCarrierConfigN1Control()).thenReturn(true); + + mPhoneUT.mCi = mMockCi; + for (int i = 0; i < 2; i++) { + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray(CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + new int[]{ + CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA, + CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA}); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(Phone.EVENT_CARRIER_CONFIG_CHANGED)); + processAllMessages(); + + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mMockCi, times(i + 1)).isN1ModeEnabled(messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), null, new RuntimeException()); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + + verify(mMockCi, never()).setN1ModeEnabled(anyBoolean(), any()); + } + } + + @Test + public void testNrCapabilityChanged_firstRequest_ImsChanges() { + when(mFeatureFlags.enableCarrierConfigN1Control()).thenReturn(true); + + mPhoneUT.mCi = mMockCi; + Message passthroughMessage = mTestHandler.obtainMessage(0xC0FFEE); + + mPhoneUT.setN1ModeEnabled(false, passthroughMessage); + processAllMessages(); + + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mMockCi, times(1)).isN1ModeEnabled(messageCaptor.capture()); + assertEquals(messageCaptor.getValue().obj, passthroughMessage); + AsyncResult.forMessage(messageCaptor.getValue(), Boolean.TRUE, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + + verify(mMockCi, times(1)).setN1ModeEnabled(eq(false), messageCaptor.capture()); + assertEquals(messageCaptor.getValue().obj, passthroughMessage); + AsyncResult.forMessage(messageCaptor.getValue(), null, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + + // Verify the return message was received + ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); + verify(mTestHandler, times(1)).sendMessageAtTime(messageArgumentCaptor.capture(), + anyLong()); + assertEquals(messageArgumentCaptor.getValue(), passthroughMessage); + + mPhoneUT.setN1ModeEnabled(true, null); + processAllMessages(); + + verify(mMockCi, times(1)).isN1ModeEnabled(any()); // not called again + verify(mMockCi, times(1)).setN1ModeEnabled(eq(true), messageCaptor.capture()); + AsyncResult.forMessage(messageCaptor.getValue(), null, null); + messageCaptor.getValue().sendToTarget(); + processAllMessages(); + } + private void setupForWpsCallTest() throws Exception { mSST.mSS = mServiceState; doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); @@ -2595,4 +2731,210 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).getNetworkSelectionMode(any(Message.class)); verify(mSimulatedCommandsVerifier).setNetworkSelectionModeAutomatic(any(Message.class)); } + + /** + * Verify the ImeiMappingChange and EVENT_GET_DEVICE_IMEI_CHANGE_DONE are handled properly. + */ + @Test + public void testChangeInPrimaryImei() { + // Initially assign the primaryImei and test it. + Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE); + ImeiInfo imeiInfo = new ImeiInfo(); + imeiInfo.imei = FAKE_IMEI; + imeiInfo.svn = FAKE_IMEISV; + imeiInfo.type = ImeiInfo.ImeiType.PRIMARY; + AsyncResult.forMessage(message, imeiInfo, null); + mPhoneUT.handleMessage(message); + assertEquals(Phone.IMEI_TYPE_PRIMARY, mPhoneUT.getImeiType()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); + + // Now update the same one to secondary and check whether it is reflecting or not. + message = mPhoneUT.obtainMessage(Phone.EVENT_IMEI_MAPPING_CHANGED); + imeiInfo.imei = FAKE_IMEI; + imeiInfo.svn = FAKE_IMEISV; + imeiInfo.type = ImeiInfo.ImeiType.SECONDARY; + AsyncResult.forMessage(message, imeiInfo, null); + mPhoneUT.handleMessage(message); + assertEquals(Phone.IMEI_TYPE_SECONDARY, mPhoneUT.getImeiType()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); + } + + @Test + public void testCellularIdentifierDisclosureFlagOff() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(false); + + GsmCdmaPhone phoneUT = + new GsmCdmaPhone( + mContext, + mSimulatedCommands, + mNotifier, + true, + 0, + PhoneConstants.PHONE_TYPE_GSM, + mTelephonyComponentFactory, + (c, p) -> mImsManager, + mFeatureFlags); + phoneUT.mCi = mMockCi; + + verify(mMockCi, never()) + .registerForCellularIdentifierDisclosures( + any(Handler.class), anyInt(), any(Object.class)); + } + + @Test + public void testCellularIdentifierDisclosureFlagOn() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true); + + Phone phoneUT = + new GsmCdmaPhone( + mContext, + mMockCi, + mNotifier, + true, + 0, + PhoneConstants.PHONE_TYPE_GSM, + mTelephonyComponentFactory, + (c, p) -> mImsManager, + mFeatureFlags); + + verify(mMockCi, times(1)) + .registerForCellularIdentifierDisclosures( + eq(phoneUT), + eq(Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE), + nullable(Object.class)); + } + + @Test + public void testCellularIdentifierDisclosure_disclosureEventAddedToNotifier() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true); + + Phone phoneUT = + new GsmCdmaPhone( + mContext, + mMockCi, + mNotifier, + true, + 0, + PhoneConstants.PHONE_TYPE_GSM, + mTelephonyComponentFactory, + (c, p) -> mImsManager, + mFeatureFlags); + + CellularIdentifierDisclosure disclosure = + new CellularIdentifierDisclosure( + CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + phoneUT.sendMessage( + mPhoneUT.obtainMessage( + Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE, + new AsyncResult(null, disclosure, null))); + processAllMessages(); + + verify(mIdentifierDisclosureNotifier, times(1)).addDisclosure(eq(disclosure)); + } + + @Test + public void testCellularIdentifierDisclosure_disclosureEventNull() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true); + + Phone phoneUT = + new GsmCdmaPhone( + mContext, + mMockCi, + mNotifier, + true, + 0, + PhoneConstants.PHONE_TYPE_GSM, + mTelephonyComponentFactory, + (c, p) -> mImsManager, + mFeatureFlags); + + phoneUT.sendMessage( + mPhoneUT.obtainMessage( + Phone.EVENT_CELL_IDENTIFIER_DISCLOSURE, new AsyncResult(null, null, null))); + processAllMessages(); + + verify(mIdentifierDisclosureNotifier, never()) + .addDisclosure(any(CellularIdentifierDisclosure.class)); + } + + @Test + public void testCellularIdentifierDisclosure_noModemCallOnRadioAvailable_FlagOff() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(false); + GsmCdmaPhone phoneUT = makeNewPhoneUT(); + assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported()); + + sendRadioAvailableToPhone(phoneUT); + + verify(mMockCi, never()).setCellularIdentifierTransparencyEnabled(anyBoolean(), + any(Message.class)); + assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported()); + } + + @Test + public void testCellularIdentifierDisclosure_unsupportedByModemOnRadioAvailable() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true); + GsmCdmaPhone phoneUT = makeNewPhoneUT(); + assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported()); + + // The following block emulates incoming messages from the modem in the case that + // the modem does not support the new HAL APIs. We expect the phone instance to attempt + // to set cipher-identifier-transparency-enabled state when the radio becomes available. + sendRadioAvailableToPhone(phoneUT); + verify(mMockCi, times(1)).setCellularIdentifierTransparencyEnabled(anyBoolean(), + any(Message.class)); + sendRequestNotSupportedToPhone(phoneUT, EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE); + + assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported()); + } + + @Test + public void testCellularIdentifierDisclosure_supportedByModem() { + when(mFeatureFlags.enableIdentifierDisclosureTransparency()).thenReturn(true); + GsmCdmaPhone phoneUT = makeNewPhoneUT(); + assertFalse(phoneUT.isIdentifierDisclosureTransparencySupported()); + + // The following block emulates incoming messages from the modem in the case that + // the modem supports the new HAL APIs. We expect the phone instance to attempt + // to set cipher-identifier-transparency-enabled state when the radio becomes available. + sendRadioAvailableToPhone(phoneUT); + verify(mMockCi, times(1)).setCellularIdentifierTransparencyEnabled(anyBoolean(), + any(Message.class)); + sendIdentifierDisclosureEnabledSuccessToPhone(phoneUT); + + assertTrue(phoneUT.isIdentifierDisclosureTransparencySupported()); + } + + private void sendRadioAvailableToPhone(GsmCdmaPhone phone) { + phone.sendMessage(phone.obtainMessage(EVENT_RADIO_AVAILABLE, + new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); + processAllMessages(); + } + + private void sendRequestNotSupportedToPhone(GsmCdmaPhone phone, int eventId) { + phone.sendMessage(phone.obtainMessage(eventId, new AsyncResult(null, null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED)))); + processAllMessages(); + } + + private void sendIdentifierDisclosureEnabledSuccessToPhone(GsmCdmaPhone phone) { + phone.sendMessage(phone.obtainMessage(EVENT_SET_IDENTIFIER_DISCLOSURE_ENABLED_DONE, + new AsyncResult(null, null, null))); + processAllMessages(); + } + + private GsmCdmaPhone makeNewPhoneUT() { + return new GsmCdmaPhone( + mContext, + mMockCi, + mNotifier, + true, + 0, + PhoneConstants.PHONE_TYPE_GSM, + mTelephonyComponentFactory, + (c, p) -> mImsManager, + mFeatureFlags); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index a41dbe15f7..7893e7867f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -198,7 +198,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { } return subscriptionInfoList; }).when(mSubscriptionManagerService).getActiveSubscriptionInfoList( - anyString(), nullable(String.class)); + anyString(), nullable(String.class), anyBoolean()); doAnswer(invocation -> { final boolean visibleOnly = (boolean) invocation.getArguments()[0]; diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java index 4538deaed0..02780bd253 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import android.os.Parcel; import android.telephony.AccessNetworkConstants.AccessNetworkType; @@ -30,6 +31,7 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import java.util.ArrayList; +import java.util.List; /** Unit tests for {@link NetworkScanRequest}. */ public class NetworkScanRequestTest { @@ -37,6 +39,137 @@ public class NetworkScanRequestTest { @Test @SmallTest public void testParcel() { + NetworkScanRequest nsq = createNetworkScanRequest(); + + Parcel p = Parcel.obtain(); + nsq.writeToParcel(p, 0); + p.setDataPosition(0); + + NetworkScanRequest newNsq = NetworkScanRequest.CREATOR.createFromParcel(p); + assertEquals(nsq, newNsq); + } + + @Test + @SmallTest + public void testEquals_identity_allFieldsNonNull() { + NetworkScanRequest nsq = createNetworkScanRequest(); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_identify_nullRadioAccessSpecifiers() { + NetworkScanRequest nsq = createNetworkScanRequest(null, List.of("310480")); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_identify_emptyRadioAccessSpecifiers() { + NetworkScanRequest nsq = createNetworkScanRequest(new RadioAccessSpecifier[]{}, + List.of("310480")); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_identify_nullPlmns() { + NetworkScanRequest nsq = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, null); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_identify_emptyPlmns() { + NetworkScanRequest nsq = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, List.of()); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_identify_nullRasAndPlmns() { + NetworkScanRequest nsq = createNetworkScanRequest(null, null); + + assertEquals(nsq, nsq); + } + + @Test + @SmallTest + public void testEquals_sameValues_allFieldsNonNull() { + NetworkScanRequest nsq1 = createNetworkScanRequest(); + NetworkScanRequest nsq2 = createNetworkScanRequest(); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_sameValues_nullRadioAccessSpecifiers() { + NetworkScanRequest nsq1 = createNetworkScanRequest(null, List.of("310480")); + NetworkScanRequest nsq2 = createNetworkScanRequest(null, List.of("310480")); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_sameValues_emptyRadioAccessSpecifiers() { + NetworkScanRequest nsq1 = createNetworkScanRequest(new RadioAccessSpecifier[]{}, + List.of("310480")); + NetworkScanRequest nsq2 = createNetworkScanRequest(new RadioAccessSpecifier[]{}, + List.of("310480")); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_sameValues_nullPlmns() { + NetworkScanRequest nsq1 = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, null); + NetworkScanRequest nsq2 = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, null); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_sameValues_emptyPlmns() { + NetworkScanRequest nsq1 = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, List.of()); + NetworkScanRequest nsq2 = createNetworkScanRequest(new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkType.GERAN, null, null)}, List.of()); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_sameValues_nullRasAndPlmns() { + NetworkScanRequest nsq1 = createNetworkScanRequest(null, null); + NetworkScanRequest nsq2 = createNetworkScanRequest(null, null); + + assertEquals(nsq1, nsq2); + } + + @Test + @SmallTest + public void testEquals_plmnsInDifferentOrder_shouldNotEqual() { + NetworkScanRequest nsq1 = createNetworkScanRequest(null, List.of("123456", "987654")); + NetworkScanRequest nsq2 = createNetworkScanRequest(null, List.of("987654", "123456")); + + assertNotEquals(nsq1, nsq2); + } + + private NetworkScanRequest createNetworkScanRequest() { int ranGsm = AccessNetworkType.GERAN; int[] gsmBands = {GeranBand.BAND_T380, GeranBand.BAND_T410}; int[] gsmChannels = {1, 2, 3, 4}; @@ -46,22 +179,30 @@ public class NetworkScanRequestTest { int[] lteChannels = {5, 6, 7, 8}; RadioAccessSpecifier lte = new RadioAccessSpecifier(ranLte, lteBands, lteChannels); RadioAccessSpecifier[] ras = {gsm, lte}; + int searchPeriodicity = 70; int maxSearchTime = 200; boolean incrementalResults = true; int incrementalResultsPeriodicity = 7; + ArrayList<String> mccmncs = new ArrayList<String>(); mccmncs.add("310480"); mccmncs.add("21002"); - NetworkScanRequest nsq = new NetworkScanRequest(NetworkScanRequest.SCAN_TYPE_ONE_SHOT, ras, - searchPeriodicity, maxSearchTime, incrementalResults, - incrementalResultsPeriodicity, mccmncs); - Parcel p = Parcel.obtain(); - nsq.writeToParcel(p, 0); - p.setDataPosition(0); + return new NetworkScanRequest(NetworkScanRequest.SCAN_TYPE_ONE_SHOT, ras, + searchPeriodicity, maxSearchTime, incrementalResults, + incrementalResultsPeriodicity, mccmncs); + } - NetworkScanRequest newNsq = NetworkScanRequest.CREATOR.createFromParcel(p); - assertEquals(nsq, newNsq); + private NetworkScanRequest createNetworkScanRequest( + RadioAccessSpecifier[] radioAccessSpecifiers, List<String> plmns) { + int searchPeriodicity = 70; + int maxSearchTime = 200; + boolean incrementalResults = true; + int incrementalResultsPeriodicity = 7; + + return new NetworkScanRequest(NetworkScanRequest.SCAN_TYPE_ONE_SHOT, radioAccessSpecifiers, + searchPeriodicity, maxSearchTime, incrementalResults, + incrementalResultsPeriodicity, plmns != null ? new ArrayList<>(plmns) : null); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTrackerTest.java new file mode 100644 index 0000000000..f0ffe349b7 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTrackerTest.java @@ -0,0 +1,924 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.nullable; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.pm.PackageManager; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.UserHandle; +import android.telephony.AccessNetworkConstants; +import android.telephony.CellInfoLte; +import android.telephony.NetworkScan; +import android.telephony.NetworkScanRequest; +import android.telephony.RadioAccessSpecifier; +import android.telephony.TelephonyScanManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.Log; + +import com.android.internal.telephony.NetworkScanRequestTracker.NetworkScanRequestInfo; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Unit test for NetworkScanRequestTracker. + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NetworkScanRequestTrackerTest extends TelephonyTest { + private static final String TAG = "NetworkScanRequestTrackerTest"; + + private static final String CLIENT_PKG = "com.android.testapp"; + private static final int CLIENT_UID = 123456; + + // Keep the same as in NetworkScanRequestTracker. + // This is the only internal implementation that the UT has to depend on + // in order to fully emulate NetworkScanResult in various cases + private static final int EVENT_RECEIVE_NETWORK_SCAN_RESULT = 3; + + // Mocks + private CommandsInterface mMockCi; + + private NetworkScanRequestTracker mNetworkScanRequestTracker; + private HandlerThread mTestHandlerThread; + private Handler mHandler; + private int mScanId; + private List<Message> mMessages = new ArrayList<>(); + // Latch to make sure all messages are received before verifying. + // Default count is 1 but can override to match expected msg number + private CountDownLatch mMessageLatch = new CountDownLatch(1); + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + + mMockCi = Mockito.mock(CommandsInterface.class); + mPhone.mCi = mMockCi; + + mTestHandlerThread = new HandlerThread(TAG); + mTestHandlerThread.start(); + mHandler = new Handler(mTestHandlerThread.getLooper()) { + @Override + public void handleMessage(Message message) { + Log.d(TAG, "Received msg: " + message); + mMessages.add(Message.obtain(message)); + mMessageLatch.countDown(); + } + }; + + mNetworkScanRequestTracker = new NetworkScanRequestTracker(); + mScanId = TelephonyScanManager.INVALID_SCAN_ID; + setHasLocationPermissions(false); + assertThat(mHandler).isNotNull(); + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + stopNetworkScanIfNeeded(mScanId); + mTestHandlerThread.quit(); + mMessages.clear(); + super.tearDown(); + } + + @Test + public void testStartNetworkScan_nullRequest_shouldNeverScan() throws Exception { + NetworkScanRequest request = null; + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when the request is null!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithNullSpecifier_shouldNeverScan() throws Exception { + RadioAccessSpecifier[] specifiers = null; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when no RadioAccessSpecifier is provided!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithEmptySpecifier_shouldNeverScan() throws Exception { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{}; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when empty RadioAccessSpecifier is " + + "provided!")).startNetworkScan( + any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooManySpecifiers_shouldNeverScan() + throws Exception { + // More than NetworkScanRequest.MAX_RADIO_ACCESS_NETWORKS (8) + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_T380}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_T410}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_450}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_480}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_710}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_750}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_T810}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_850}, null), + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + new int[]{AccessNetworkConstants.GeranBand.BAND_P900}, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when request with too many " + + "RadioAccessSpecifiers!")).startNetworkScan( + any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooManyBands_shouldNeverScan() throws Exception { + // More than NetworkScanRequest.MAX_BANDS (8) + int[] bands = new int[]{ + AccessNetworkConstants.GeranBand.BAND_T380, + AccessNetworkConstants.GeranBand.BAND_T410, + AccessNetworkConstants.GeranBand.BAND_450, + AccessNetworkConstants.GeranBand.BAND_480, + AccessNetworkConstants.GeranBand.BAND_710, + AccessNetworkConstants.GeranBand.BAND_750, + AccessNetworkConstants.GeranBand.BAND_T810, + AccessNetworkConstants.GeranBand.BAND_850, + AccessNetworkConstants.GeranBand.BAND_P900, + }; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + bands, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when request with too many bands!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooManyChannels_shouldNeverScan() throws Exception { + // More than NetworkScanRequest.MAX_CHANNELS (32) + int[] channels = + new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + }; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, channels), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when request with too many channels!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + + } + + @Test + public void testStartNetworkScan_requestWithUnsupportedRan_shouldNeverScan() throws Exception { + int[] unsupportedRans = new int[]{ + AccessNetworkConstants.AccessNetworkType.UNKNOWN, + AccessNetworkConstants.AccessNetworkType.CDMA2000, + AccessNetworkConstants.AccessNetworkType.IWLAN, + }; + for (int ran : unsupportedRans) { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(ran, null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + int scanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan with unsupported RAN " + + ran + "!")).startNetworkScan(any(), any()); + + // Nothing is needed to clean up on success. + // This is just for failure cases when startNetworkScan was issued. + stopNetworkScanIfNeeded(scanId); + } + } + + @Test + public void testStartNetworkScan_requestWithTooSmallPeriodicity_shouldNeverScan() + throws Exception { + int searchPeriodicity = NetworkScanRequest.MIN_SEARCH_PERIODICITY_SEC - 1; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + searchPeriodicity /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when request with too small periodicity!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooLargePeriodicity_shouldNeverScan() + throws Exception { + int searchPeriodicity = NetworkScanRequest.MAX_SEARCH_MAX_SEC + 1; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + searchPeriodicity /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan with too large periodicity!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooSmallIncPeriodicity_shouldNeverScan() + throws Exception { + int incPeriodicity = NetworkScanRequest.MIN_INCREMENTAL_PERIODICITY_SEC - 1; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + incPeriodicity /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan with too small incremental results " + + "periodicity!")).startNetworkScan( + any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestWithTooLargeIncPeriodicity_shouldNeverScan() + throws Exception { + int incPeriodicity = NetworkScanRequest.MAX_INCREMENTAL_PERIODICITY_SEC + 1; + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + incPeriodicity /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan with too large incremental periodicity!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestPeriodBiggerThanMax_shouldNeverScan() throws Exception { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 61 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when periodicity is larger than max search" + + " time!")).startNetworkScan( + any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestIncPeriodBiggerThanMax_shouldNeverScan() + throws Exception { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 61 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when incremental results periodicity is " + + "larger than max search time!")).startNetworkScan( + any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_requestTooManyPlmns_shouldNeverScan() throws Exception { + // More than NetworkScanRequest.MAX_MCC_MNC_LIST_SIZE (20) PLMNs + List<String> plmns = List.of("11110", "11111", "11112", "11113", "11114", "11115", "11116", + "11117", "11118", "11119", "11120", "11121", "11122", "11123", "11124", "11125", + "11126", "11127", "11128", "11129", "11130", "11131"); + + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.GERAN, + null, null), + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, /* specifiers */ + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + new ArrayList<>(plmns) /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + + mScanId = mNetworkScanRequestTracker.startNetworkScan(true, request, messenger, + mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + verify(mPhone, never().description( + "Phone should never start network scan when request with too many PLMNs!")) + .startNetworkScan(any(), any()); + verifyMessage(TelephonyScanManager.CALLBACK_SCAN_ERROR, NetworkScan.ERROR_INVALID_SCAN, + mScanId, null); + } + + @Test + public void testStartNetworkScan_succeed_returnValidScanId() throws Exception { + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + verify(mPhone).startNetworkScan(any(), any()); + assertThat(mScanId).isNotEqualTo(TelephonyScanManager.INVALID_SCAN_ID); + } + + @Test + public void testStartNetworkScan_succeed_deathRecipientIsLinked() throws Exception { + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + verify(mIBinder).linkToDeath(any(), anyInt()); + } + + @Test + public void testStartNetworkScan_multipleRequests_scanIdShouldNotRepeat() throws Exception { + int firstScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + stopNetworkScanIfNeeded(firstScanId); + + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + assertThat(mScanId).isNotEqualTo(firstScanId); + } + + @Test + public void testStartNetworkScan_singleResultAndSuccess_allMessagesNotified() throws Exception { + mMessageLatch = new CountDownLatch(2); // 2 messages expected + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + // Only one result and it is completed. + verifyStartNetworkScanAndEmulateScanResult( + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_COMPLETE, + NetworkScan.SUCCESS, List.of(new CellInfoLte()))); + + verifyMessages( + // One RESTRICTED_SCAN_RESULTS msg follows by COMPLETE msg + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, + NetworkScan.SUCCESS, mScanId, null) + ); + } + + @Test + public void testStartNetworkScan_resultFromCopiedRequest_noMessagesNotified() throws Exception { + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + // Scan result came but with copied (instead of original) NetworkScanRequestInfo + NetworkScanRequestInfo obsoletedNsri = createNetworkScanRequestInfo(mScanId); + verifyStartNetworkScanAndEmulateScanResult(obsoletedNsri, + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_COMPLETE, + NetworkScan.SUCCESS, List.of(new CellInfoLte()))); + + // No message should send to client + verifyMessages(); + } + + @Test + public void testStartNetworkScan_multiResultsAndSuccess_allMessagesNotified() throws Exception { + mMessageLatch = new CountDownLatch(4); // 4 messages expected + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + verifyStartNetworkScanAndEmulateScanResult( + // First two results arrived but did not complete + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_PARTIAL, + NetworkScan.SUCCESS, List.of(new CellInfoLte())), + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_PARTIAL, + NetworkScan.SUCCESS, List.of(new CellInfoLte())), + // Third result arrived and completed + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_COMPLETE, + NetworkScan.SUCCESS, List.of(new CellInfoLte()))); + + verifyMessages( + // Same number of SCAN_RESULTS and end with COMPLETE messages. + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, + NetworkScan.SUCCESS, mScanId, null) + ); + } + + @Test + public void testStartNetworkScan_modemError_allMessagesNotified() throws Exception { + mMessageLatch = new CountDownLatch(3); // 3 messages expected + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + verifyStartNetworkScanAndEmulateScanResult( + // First result arrived but did not complete + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_PARTIAL, + NetworkScan.SUCCESS, List.of(new CellInfoLte())), + // Final result arrived and indicated modem error + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_COMPLETE, + NetworkScan.ERROR_MODEM_ERROR, List.of(new CellInfoLte()))); + + verifyMessages( + // First SUCCESS scan result + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + // Final ERROR messages + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_RESTRICTED_SCAN_RESULTS, + NetworkScan.ERROR_MODEM_ERROR, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_ERROR, + NetworkScan.ERROR_MODEM_ERROR, mScanId, null) + ); + } + + @Test + public void testStartNetworkScan_clientDied_shouldStopScan() throws Exception { + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + verifyStartNetworkScanAndEmulateBinderDied(); + + verify(mPhone).stopNetworkScan(any()); + } + + @Test + public void testStopNetworkScan_invalidScanId_throwIllegalArgumentException() throws Exception { + final int invalidScanId = 1000; + assertThrows(IllegalArgumentException.class, + () -> mNetworkScanRequestTracker.stopNetworkScan(invalidScanId, CLIENT_UID)); + } + + @Test + public void testStopNetworkScan_fromOtherUid_throwIllegalArgumentException() throws Exception { + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + + assertThrows(IllegalArgumentException.class, + () -> mNetworkScanRequestTracker.stopNetworkScan(mScanId, 654321)); + } + + @Test + public void testStopNetworkScan_scanIdAndUidMatchWithoutError_shouldUnregister() + throws Exception { + mMessageLatch = new CountDownLatch(1); // 1 message expected + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + mNetworkScanRequestTracker.stopNetworkScan(mScanId, CLIENT_UID); + processAllMessages(); + + // No error during stopping network scan + verifyStopNetworkScanAndEmulateResult(null /* commandException */); + + verify(mPhone.mCi).unregisterForNetworkScanResult(any()); + verify(mPhone.mCi).unregisterForModemReset(any()); + verify(mPhone.mCi).unregisterForNotAvailable(any()); + + verifyMessages( + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, + NetworkScan.SUCCESS, mScanId, null) + ); + } + + @Test + public void testStopNetworkScan_withError_reportTranslatedScanError() + throws Exception { + mMessageLatch = new CountDownLatch(1); // 1 message expected + mScanId = scanNetworkWithOneShot(true /* renounceFineLocationAccess */); + mNetworkScanRequestTracker.stopNetworkScan(mScanId, CLIENT_UID); + processAllMessages(); + + // No memory error during stopping network scan + verifyStopNetworkScanAndEmulateResult( + new CommandException(CommandException.Error.NO_MEMORY)); + + verifyMessages( + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_ERROR, + NetworkScan.ERROR_MODEM_ERROR, mScanId, null) + ); + } + + // -- Test cases below cover scenarios when caller has FINE_LOCATION permission -- + @Test + public void testStartNetworkScan_withLocationPermission_allMessagesNotified() + throws Exception { + setHasLocationPermissions(true); + mMessageLatch = new CountDownLatch(2); // 2 messages expected + mScanId = scanNetworkWithOneShot(false /* renounceFineLocationAccess */); + + // Only one result and it is completed. + verifyStartNetworkScanAndEmulateScanResult( + new NetworkScanResult(NetworkScanResult.SCAN_STATUS_COMPLETE, + NetworkScan.SUCCESS, List.of(new CellInfoLte()))); + + verifyMessages( + // One SCAN_RESULTS msg follows by COMPLETE msg + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_RESULTS, + NetworkScan.SUCCESS, mScanId, null), + Message.obtain(mHandler, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, + NetworkScan.SUCCESS, mScanId, null) + ); + } + + private void stopNetworkScanIfNeeded(int scanId) { + if (scanId != TelephonyScanManager.INVALID_SCAN_ID) { + try { + mNetworkScanRequestTracker.stopNetworkScan(mScanId, CLIENT_UID); + processAllMessages(); + } catch (IllegalArgumentException ignored) { + } + } + } + + private void verifyMessages(Message... messages) { + try { + mMessageLatch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new AssertionError("Interrupted while latch is wait for messages"); + } + + assertThat(mMessages.size()).isEqualTo(messages.length); + for (int i = 0; i < messages.length; i++) { + // We only care about what/arg1/arg2/obj by now + assertThat(mMessages.get(i).what).isEqualTo(messages[i].what); + assertThat(mMessages.get(i).arg1).isEqualTo(messages[i].arg1); + assertThat(mMessages.get(i).arg2).isEqualTo(messages[i].arg2); + assertThat(mMessages.get(i).obj).isEqualTo(messages[i].obj); + } + } + + /** + * Verify only one Message with better readability + */ + private void verifyMessage(int what, int arg1, int arg2, Object obj) { + verifyMessages(Message.obtain(mHandler, what, arg1, arg2, obj)); + } + + + /** + * Verify both {@link CommandsInterface#startNetworkScan(NetworkScanRequest, Message)} and + * {@link CommandsInterface#registerForNetworkScanResult(Handler, int, Object)} and sends + * emulated {@link NetworkScanResult} with original NetworkScanRequestInfo back through the + * captures. + */ + private void verifyStartNetworkScanAndEmulateScanResult( + NetworkScanResult... networkScanResults) { + NetworkScanRequestInfo nsri = verifyStartNetworkScanAndGetNetworkScanInfo(); + + sendEmulatedScanResult(nsri, networkScanResults); + } + + /** + * Similar as verifyStartNetworkScanAndEmulateScanResult(NetworkScanResult...) above but + * allows to set the customized NetworkScanRequestInfo other than original one. + */ + private void verifyStartNetworkScanAndEmulateScanResult( + NetworkScanRequestInfo nsri, + NetworkScanResult... networkScanResults) { + // Ignore the original NSRI returned + verifyStartNetworkScanAndGetNetworkScanInfo(); + + sendEmulatedScanResult(nsri, networkScanResults); + } + + private void sendEmulatedScanResult(NetworkScanRequestInfo nsri, + NetworkScanResult... networkScanResults) { + ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class); + verify(mPhone.mCi).registerForNetworkScanResult(handlerCaptor.capture(), anyInt(), any()); + Handler handler = handlerCaptor.getValue(); + + for (NetworkScanResult networkScanResult : networkScanResults) { + Message result = Message.obtain(handler, EVENT_RECEIVE_NETWORK_SCAN_RESULT, nsri); + AsyncResult.forMessage(result, networkScanResult, null); + result.sendToTarget(); + } + processAllMessages(); + } + + /** + * Verify {@link CommandsInterface#startNetworkScan(NetworkScanRequest, Message)} and emulate + * client process died through the captured {@link IBinder.DeathRecipient}. + */ + private void verifyStartNetworkScanAndEmulateBinderDied() { + IBinder.DeathRecipient nsri = verifyStartNetworkScanAndGetNetworkScanInfo(); + nsri.binderDied(); + processAllMessages(); + } + + /** + * Verify {@link Phone#startNetworkScan(NetworkScanRequest, Message)} and + * capture the NetworkScanRequestInfo for further usage. + */ + private NetworkScanRequestInfo verifyStartNetworkScanAndGetNetworkScanInfo() { + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mPhone).startNetworkScan(any(), messageCaptor.capture()); + Message responseMessage = messageCaptor.getValue(); + // NetworkScanRequestInfo is not public and can only be treated as IBinder.DeathRecipient + NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) responseMessage.obj; + AsyncResult.forMessage(responseMessage, nsri, null); + responseMessage.sendToTarget(); + processAllMessages(); + return nsri; + } + + /** + * Verify {@link Phone#stopNetworkScan} and emulate the result (succeed or failures) + * through the {@code commandException}. + */ + private void verifyStopNetworkScanAndEmulateResult(CommandException commandException) { + ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mPhone).stopNetworkScan(messageCaptor.capture()); + Message responseMessage = messageCaptor.getValue(); + // NetworkScanRequestInfo is not public and can only be treated as Object here + Object nsri = responseMessage.obj; + AsyncResult.forMessage(responseMessage, nsri, commandException); + responseMessage.sendToTarget(); + processAllMessages(); + } + + private int scanNetworkWithOneShot(boolean renounceFineLocationAccess) { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null, + null) + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + int scanId = mNetworkScanRequestTracker.startNetworkScan(renounceFineLocationAccess, + request, messenger, mIBinder, mPhone, CLIENT_UID, -1, CLIENT_PKG); + processAllMessages(); + + return scanId; + } + + private NetworkScanRequestInfo createNetworkScanRequestInfo(int scanId) { + RadioAccessSpecifier[] specifiers = new RadioAccessSpecifier[]{ + new RadioAccessSpecifier(AccessNetworkConstants.AccessNetworkType.EUTRAN, null, + null) + }; + NetworkScanRequest request = new NetworkScanRequest( + NetworkScanRequest.SCAN_TYPE_ONE_SHOT, + specifiers, + 5 /* searchPeriodicity */, + 60 /* maxSearchTime in seconds */, + true /* incrementalResults */, + 5 /* incrementalResultsPeriodicity */, + null /* PLMNs */); + Messenger messenger = new Messenger(mHandler); + return mNetworkScanRequestTracker.new NetworkScanRequestInfo(request, messenger, mIBinder, + scanId, mPhone, CLIENT_UID, -1, CLIENT_PKG, true); + } + + private void setHasLocationPermissions(boolean hasPermission) { + if (!hasPermission) { + // System location off, LocationAccessPolicy#checkLocationPermission returns DENIED_SOFT + when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))) + .thenReturn(false); + } else { + // Turn on all to let LocationAccessPolicy#checkLocationPermission returns ALLOWED + when(mContext.checkPermission(eq(Manifest.permission.ACCESS_FINE_LOCATION), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + when(mContext.checkPermission(eq(Manifest.permission.ACCESS_COARSE_LOCATION), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_FINE_LOCATION), + anyInt(), anyString(), nullable(String.class), nullable(String.class))) + .thenReturn(AppOpsManager.MODE_ALLOWED); + when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_COARSE_LOCATION), + anyInt(), anyString(), nullable(String.class), nullable(String.class))) + .thenReturn(AppOpsManager.MODE_ALLOWED); + when(mLocationManager.isLocationEnabledForUser(any(UserHandle.class))).thenReturn(true); + when(mContext.checkPermission(eq(Manifest.permission.INTERACT_ACROSS_USERS_FULL), + anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_GRANTED); + } + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java index 700a246815..4f2d8dbebb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java @@ -43,6 +43,8 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.flags.FeatureFlags; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -62,6 +64,7 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 1; PhoneConfigurationManager mPcm; + private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -69,6 +72,7 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { mHandler = mock(Handler.class); mMockCi0 = mock(CommandsInterface.class); mMockCi1 = mock(CommandsInterface.class); + mFeatureFlags = Mockito.mock(FeatureFlags.class); mPhone1 = mock(Phone.class); mMi = mock(PhoneConfigurationManager.MockableInterface.class); mPhone.mCi = mMockCi0; @@ -89,7 +93,7 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { private void init(int numOfSim) throws Exception { doReturn(numOfSim).when(mTelephonyManager).getActiveModemCount(); replaceInstance(PhoneConfigurationManager.class, "sInstance", null, null); - mPcm = PhoneConfigurationManager.init(mContext); + mPcm = PhoneConfigurationManager.init(mContext, mFeatureFlags); replaceInstance(PhoneConfigurationManager.class, "mMi", mPcm, mMi); processAllMessages(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index 2f3bbf713f..3c7e0b6af0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -216,6 +216,12 @@ public class PhoneNumberUtilsTest { assertNull(PhoneNumberUtils.toCallerIDMinMatch(null)); assertNull(PhoneNumberUtils.getStrippedReversed(null)); assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1)); + + // Test for known potential bad extraction of post dial portion. + assertEquals(";123456", + PhoneNumberUtils.extractPostDialPortion("6281769222;123456")); + assertEquals("6281769222", PhoneNumberUtils.extractNetworkPortion( + "6281769222;123456")); } @SmallTest @@ -856,4 +862,20 @@ public class PhoneNumberUtilsTest { assertEquals(TtsSpan.TYPE_TELEPHONE, ttsSpan.getType()); assertEquals(expected, ttsSpan.getArgs().getString(TtsSpan.ARG_NUMBER_PARTS)); } + + @SmallTest + @Test + public void testWpsCallNumber() { + // Test number without special symbols. + assertFalse(PhoneNumberUtils.isWpsCallNumber("12345678")); + + // TTS number should not be recognized as wps. + assertFalse(PhoneNumberUtils.isWpsCallNumber("*23212345678")); + assertFalse(PhoneNumberUtils.isWpsCallNumber("*232#12345678")); + + // Check WPS valid numbers + assertTrue(PhoneNumberUtils.isWpsCallNumber("*27212345678")); + assertTrue(PhoneNumberUtils.isWpsCallNumber("*31#*27212345678")); + assertTrue(PhoneNumberUtils.isWpsCallNumber("#31#*27212345678")); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java index 2396d1dcc5..bfe9649e78 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java @@ -64,7 +64,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_READ_IT import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_RESET_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_ITEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_SMS_MEMORY_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING; @@ -82,10 +81,8 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIGNAL_STR import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIM_AUTHENTICATION; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIM_CLOSE_CHANNEL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIM_OPEN_CHANNEL; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UDUB; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_RADIO_TECH; @@ -105,17 +102,18 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ApplicationInfo; import android.hardware.radio.V1_0.Carrier; import android.hardware.radio.V1_0.CdmaSmsMessage; -import android.hardware.radio.V1_0.DataProfileInfo; import android.hardware.radio.V1_0.GsmSmsMessage; import android.hardware.radio.V1_0.ImsSmsMessage; import android.hardware.radio.V1_0.NvWriteItem; @@ -130,6 +128,7 @@ import android.net.InetAddresses; import android.net.LinkAddress; import android.os.AsyncResult; import android.os.Handler; +import android.os.HandlerThread; import android.os.IPowerManager; import android.os.IThermalService; import android.os.Looper; @@ -139,6 +138,7 @@ import android.os.RemoteException; import android.os.WorkSource; import android.service.carrier.CarrierIdentifier; import android.telephony.AccessNetworkConstants; +import android.telephony.CellConfigLte; import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; import android.telephony.CellIdentityLte; @@ -158,11 +158,10 @@ import android.telephony.CellSignalStrengthLte; import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; +import android.telephony.ClosedSubscriberGroupInfo; import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessFamily; import android.telephony.RadioAccessSpecifier; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SmsManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -199,6 +198,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @RunWith(AndroidTestingRunner.class) @@ -220,13 +221,10 @@ public class RILTest extends TelephonyTest { private RadioSimProxy mSimProxy; private RadioModemProxy mRadioModemProxy; - private Map<Integer, HalVersion> mHalVersionV10 = new HashMap<>(); - private Map<Integer, HalVersion> mHalVersionV11 = new HashMap<>(); - private Map<Integer, HalVersion> mHalVersionV12 = new HashMap<>(); - private Map<Integer, HalVersion> mHalVersionV13 = new HashMap<>(); private Map<Integer, HalVersion> mHalVersionV14 = new HashMap<>(); private Map<Integer, HalVersion> mHalVersionV15 = new HashMap<>(); private Map<Integer, HalVersion> mHalVersionV16 = new HashMap<>(); + private Map<Integer, HalVersion> mHalVersionV20 = new HashMap<>(); private Map<Integer, HalVersion> mHalVersionV21 = new HashMap<>(); private RIL mRILInstance; @@ -243,25 +241,21 @@ public class RILTest extends TelephonyTest { private static final int CI = 268435456; private static final int CID = 65535; private static final int CQI = 2147483647; + private static final int CQI_TABLE_INDEX = 1; private static final int DBM = -74; private static final int EARFCN = 262140; - private static final List<Integer> BANDS = Arrays.asList(1, 2); + private static final ArrayList<Integer> BANDS = new ArrayList<>(Arrays.asList(1, 2)); private static final int BANDWIDTH = 5000; private static final int ECIO = -124; - private static final String EMPTY_ALPHA_LONG = ""; - private static final String EMPTY_ALPHA_SHORT = ""; private static final int LAC = 65535; private static final int LATITUDE = 1292000; private static final int LONGITUDE = 1295000; - private static final int MCC = 120; private static final String MCC_STR = "120"; - private static final int MNC = 260; private static final String MNC_STR = "260"; private static final int NETWORK_ID = 65534; private static final int NRARFCN = 3279165; private static final int PCI = 503; private static final int PSC = 500; - private static final int RIL_TIMESTAMP_TYPE_OEM_RIL = 3; private static final int RSSNR = CellInfo.UNAVAILABLE; private static final int RSRP = -96; private static final int RSRQ = -10; @@ -277,11 +271,9 @@ public class RILTest extends TelephonyTest { private static final int TIMING_ADVANCE = 4; private static final long TIMESTAMP = 215924934; private static final int UARFCN = 690; - private static final int TYPE_CDMA = 2; - private static final int TYPE_GSM = 1; - private static final int TYPE_LTE = 3; - private static final int TYPE_WCDMA = 4; - private static final int TYPE_TD_SCDMA = 5; + private static final int CONNECTION_STATUS = CellInfo.CONNECTION_NONE; + private static final boolean ENDC_AVAILABLE = true; + private static final boolean REGISTERED = true; private static final int PROFILE_ID = 0; private static final String APN = "apn"; @@ -298,7 +290,6 @@ public class RILTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_LTE); private static final int ROAMING_PROTOCOL = ApnSetting.PROTOCOL_IPV6; private static final int MTU = 1234; - private static final boolean PERSISTENT = true; private static final String[] ADDITIONAL_PLMNS = new String[] {"00101", "001001", "12345"}; @@ -341,31 +332,26 @@ public class RILTest extends TelephonyTest { RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE), Phone.PREFERRED_CDMA_SUBSCRIPTION, 0, proxies); mRILUnderTest = spy(mRILInstance); - doReturn(mRadioProxy).when(mRILUnderTest).getRadioProxy(any()); - doReturn(mDataProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioDataProxy.class), - any()); + doReturn(mRadioProxy).when(mRILUnderTest).getRadioProxy(); + doReturn(mDataProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioDataProxy.class)); doReturn(mNetworkProxy).when(mRILUnderTest).getRadioServiceProxy( - eq(RadioNetworkProxy.class), any()); - doReturn(mSimProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioSimProxy.class), - any()); + eq(RadioNetworkProxy.class)); + doReturn(mSimProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioSimProxy.class)); doReturn(mRadioModemProxy).when(mRILUnderTest).getRadioServiceProxy( - eq(RadioModemProxy.class), any()); + eq(RadioModemProxy.class)); doReturn(false).when(mDataProxy).isEmpty(); doReturn(false).when(mNetworkProxy).isEmpty(); doReturn(false).when(mSimProxy).isEmpty(); doReturn(false).when(mRadioModemProxy).isEmpty(); try { for (int service = RIL.MIN_SERVICE_IDX; service <= RIL.MAX_SERVICE_IDX; service++) { - mHalVersionV10.put(service, new HalVersion(1, 0)); - mHalVersionV11.put(service, new HalVersion(1, 1)); - mHalVersionV12.put(service, new HalVersion(1, 2)); - mHalVersionV13.put(service, new HalVersion(1, 3)); mHalVersionV14.put(service, new HalVersion(1, 4)); mHalVersionV15.put(service, new HalVersion(1, 5)); mHalVersionV16.put(service, new HalVersion(1, 6)); + mHalVersionV20.put(service, new HalVersion(2, 0)); mHalVersionV21.put(service, new HalVersion(2, 1)); } - replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV10); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV14); } catch (Exception e) { } } @@ -511,7 +497,6 @@ public class RILTest extends TelephonyTest { @FlakyTest @Test public void testSupplySimDepersonalization() throws Exception { - String controlKey = "1234"; PersoSubState persoType = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_PUK; @@ -530,11 +515,7 @@ public class RILTest extends TelephonyTest { mRILUnderTest.supplySimDepersonalization(persoType, controlKey, obtainMessage()); verify(mRadioProxy).supplySimDepersonalization( mSerialNumberCaptor.capture(), - eq((int) invokeMethod( - mRILInstance, - "convertPersoTypeToHalPersoType", - new Class<?>[] {PersoSubState.class}, - new Object[] {persoType})), + RILUtils.convertToHalPersoType(persoType), eq(controlKey)); verifyRILResponse( mRILUnderTest, @@ -568,11 +549,7 @@ public class RILTest extends TelephonyTest { mRILUnderTest.supplySimDepersonalization(persoType, controlKey, obtainMessage()); verify(mRadioProxy).supplySimDepersonalization( mSerialNumberCaptor.capture(), - eq((int) invokeMethod( - mRILInstance, - "convertPersoTypeToHalPersoType", - new Class<?>[] {PersoSubState.class}, - new Object[] {persoType})), + RILUtils.convertToHalPersoType(persoType), eq(controlKey)); verifyRILResponse( mRILUnderTest, @@ -1166,18 +1143,11 @@ public class RILTest extends TelephonyTest { .setApnSetting(apnSetting) .setPreferred(false) .build(); - boolean isRoaming = false; - mRILUnderTest.setInitialAttachApn(dataProfile, isRoaming, obtainMessage()); - verify(mRadioProxy).setInitialAttachApn( + mRILUnderTest.setInitialAttachApn(dataProfile, obtainMessage()); + verify(mRadioProxy).setInitialAttachApn_1_4( mSerialNumberCaptor.capture(), - eq((DataProfileInfo) invokeMethod( - mRILInstance, - "convertToHalDataProfile10", - new Class<?>[] {DataProfile.class}, - new Object[] {dataProfile})), - eq(dataProfile.isPersistent()), - eq(isRoaming)); + eq(RILUtils.convertToHalDataProfile14(dataProfile))); verifyRILResponse( mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_SET_INITIAL_ATTACH_APN); } @@ -1318,11 +1288,7 @@ public class RILTest extends TelephonyTest { mRILUnderTest.nvResetConfig(resetType, obtainMessage()); verify(mRadioProxy).nvResetConfig( mSerialNumberCaptor.capture(), - eq((Integer) invokeMethod( - mRILInstance, - "convertToHalResetNvType", - new Class<?>[] {Integer.TYPE}, - new Object[] {resetType}))); + RILUtils.convertToHalResetNvType(resetType)); verifyRILResponse( mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_NV_RESET_CONFIG); } @@ -1377,33 +1343,6 @@ public class RILTest extends TelephonyTest { @FlakyTest @Test - public void testStartLceService() throws Exception { - int reportIntervalMs = 1000; - boolean pullMode = false; - mRILUnderTest.startLceService(reportIntervalMs, pullMode, obtainMessage()); - verify(mRadioProxy).startLceService( - mSerialNumberCaptor.capture(), eq(reportIntervalMs), eq(pullMode)); - verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_START_LCE); - } - - @FlakyTest - @Test - public void testStopLceService() throws Exception { - mRILUnderTest.stopLceService(obtainMessage()); - verify(mRadioProxy).stopLceService(mSerialNumberCaptor.capture()); - verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_STOP_LCE); - } - - @FlakyTest - @Test - public void testPullLceData() throws Exception { - mRILUnderTest.pullLceData(obtainMessage()); - verify(mRadioProxy).pullLceData(mSerialNumberCaptor.capture()); - verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_PULL_LCEDATA); - } - - @FlakyTest - @Test public void testGetModemActivityInfo() throws Exception { mRILUnderTest.getModemActivityInfo(obtainMessage(), new WorkSource()); verify(mRadioProxy).getModemActivityInfo(mSerialNumberCaptor.capture()); @@ -1606,669 +1545,741 @@ public class RILTest extends TelephonyTest { return respInfo; } + private android.hardware.radio.V1_2.CellIdentityOperatorNames getCellIdentityOperatorNames() { + android.hardware.radio.V1_2.CellIdentityOperatorNames operatorNames = + new android.hardware.radio.V1_2.CellIdentityOperatorNames(); + operatorNames.alphaLong = ALPHA_LONG; + operatorNames.alphaShort = ALPHA_SHORT; + + return operatorNames; + } + + private android.hardware.radio.V1_2.CellIdentityLte getCellIdentityLte_1_2() { + android.hardware.radio.V1_0.CellIdentityLte cellIdentity0 = + new android.hardware.radio.V1_0.CellIdentityLte(); + cellIdentity0.mcc = MCC_STR; + cellIdentity0.mnc = MNC_STR; + cellIdentity0.ci = CI; + cellIdentity0.pci = PCI; + cellIdentity0.tac = TAC; + cellIdentity0.earfcn = EARFCN; + + android.hardware.radio.V1_2.CellIdentityLte cellIdentity = + new android.hardware.radio.V1_2.CellIdentityLte(); + cellIdentity.base = cellIdentity0; + cellIdentity.operatorNames = getCellIdentityOperatorNames(); + cellIdentity.bandwidth = BANDWIDTH; + + return cellIdentity; + } + + private android.hardware.radio.V1_0.LteSignalStrength getLteSignalStrength_1_0() { + android.hardware.radio.V1_0.LteSignalStrength signalStrength = + new android.hardware.radio.V1_0.LteSignalStrength(); + signalStrength.signalStrength = RSSI_ASU; + signalStrength.rsrp = -RSRP; + signalStrength.rsrq = -RSRQ; + signalStrength.rssnr = RSSNR; + signalStrength.cqi = CQI; + signalStrength.timingAdvance = TIMING_ADVANCE; + + return signalStrength; + } + + private android.hardware.radio.V1_4.CellInfo getCellInfo_1_4ForLte() { + android.hardware.radio.V1_2.CellInfoLte cellInfo2 = + new android.hardware.radio.V1_2.CellInfoLte(); + cellInfo2.cellIdentityLte = getCellIdentityLte_1_2(); + cellInfo2.signalStrengthLte = getLteSignalStrength_1_0(); + + android.hardware.radio.V1_4.CellConfigLte cellConfig = + new android.hardware.radio.V1_4.CellConfigLte(); + cellConfig.isEndcAvailable = ENDC_AVAILABLE; + + android.hardware.radio.V1_4.CellInfoLte cellInfoLte = + new android.hardware.radio.V1_4.CellInfoLte(); + cellInfoLte.base = cellInfo2; + cellInfoLte.cellConfig = cellConfig; + + android.hardware.radio.V1_4.CellInfo cellInfo = new android.hardware.radio.V1_4.CellInfo(); + cellInfo.isRegistered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.info.lte(cellInfoLte); + + return cellInfo; + } + @Test - public void testConvertHalCellInfoListForLTE() { - android.hardware.radio.V1_0.CellInfoLte lte = new android.hardware.radio.V1_0.CellInfoLte(); - lte.cellIdentityLte.ci = CI; - lte.cellIdentityLte.pci = PCI; - lte.cellIdentityLte.tac = TAC; - lte.cellIdentityLte.earfcn = EARFCN; - lte.cellIdentityLte.mcc = MCC_STR; - lte.cellIdentityLte.mnc = MNC_STR; - lte.signalStrengthLte.signalStrength = RSSI_ASU; - lte.signalStrengthLte.rsrp = -RSRP; - lte.signalStrengthLte.rsrq = -RSRQ; - lte.signalStrengthLte.rssnr = RSSNR; - lte.signalStrengthLte.cqi = CQI; - lte.signalStrengthLte.timingAdvance = TIMING_ADVANCE; - android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo(); - record.cellInfoType = TYPE_LTE; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.lte.add(lte); + public void testConvertHalCellInfoList_1_4ForLte() { ArrayList<Object> records = new ArrayList<>(); - records.add(record); + records.add(getCellInfo_1_4ForLte()); ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); CellInfoLte cellInfoLte = (CellInfoLte) ret.get(0); - CellInfoLte expected = new CellInfoLte(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, new int[] {}, - Integer.MAX_VALUE, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthLte css = new CellSignalStrengthLte( - RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); - expected.setCellIdentity(cil); - expected.setCellSignalStrength(css); - expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN); cellInfoLte.setTimeStamp(TIMESTAMP); // override the timestamp + + CellIdentityLte cellIdentityLte = new CellIdentityLte(CI, PCI, TAC, EARFCN, new int[] {}, + BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), + null); + CellSignalStrengthLte cellSignalStrengthLte = new CellSignalStrengthLte( + RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); + CellConfigLte cellConfigLte = new CellConfigLte(ENDC_AVAILABLE); + CellInfoLte expected = new CellInfoLte(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityLte, cellSignalStrengthLte, cellConfigLte); assertEquals(expected, cellInfoLte); } - @Test - public void testConvertHalCellInfoListForGSM() { - android.hardware.radio.V1_0.CellInfoGsm cellinfo = - new android.hardware.radio.V1_0.CellInfoGsm(); - cellinfo.cellIdentityGsm.lac = LAC; - cellinfo.cellIdentityGsm.cid = CID; - cellinfo.cellIdentityGsm.bsic = BSIC; - cellinfo.cellIdentityGsm.arfcn = ARFCN; - cellinfo.cellIdentityGsm.mcc = MCC_STR; - cellinfo.cellIdentityGsm.mnc = MNC_STR; - cellinfo.signalStrengthGsm.signalStrength = RSSI_ASU; - cellinfo.signalStrengthGsm.bitErrorRate = BIT_ERROR_RATE; - cellinfo.signalStrengthGsm.timingAdvance = TIMING_ADVANCE; - android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo(); - record.cellInfoType = TYPE_GSM; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.gsm.add(cellinfo); - ArrayList<Object> records = new ArrayList<>(); - records.add(record); + private android.hardware.radio.V1_5.OptionalCsgInfo getOptionalCsgInfo() { + android.hardware.radio.V1_5.ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new android.hardware.radio.V1_5.ClosedSubscriberGroupInfo(); + closedSubscriberGroupInfo.csgIndication = CSG_INDICATION; + closedSubscriberGroupInfo.homeNodebName = HOME_NODEB_NAME; + closedSubscriberGroupInfo.csgIdentity = CSG_IDENTITY; - ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); + android.hardware.radio.V1_5.OptionalCsgInfo optionalCsgInfo = + new android.hardware.radio.V1_5.OptionalCsgInfo(); + optionalCsgInfo.csgInfo(closedSubscriberGroupInfo); - assertEquals(1, ret.size()); - CellInfoGsm cellInfoGsm = (CellInfoGsm) ret.get(0); - CellInfoGsm expected = new CellInfoGsm(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityGsm ci = new CellIdentityGsm( - LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList()); - CellSignalStrengthGsm cs = new CellSignalStrengthGsm( - RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN); - cellInfoGsm.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoGsm); + return optionalCsgInfo; + } + + private android.hardware.radio.V1_5.CellIdentityLte getCellIdentityLte_1_5() { + android.hardware.radio.V1_5.CellIdentityLte cellIdentity = + new android.hardware.radio.V1_5.CellIdentityLte(); + cellIdentity.base = getCellIdentityLte_1_2(); + cellIdentity.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); + cellIdentity.optionalCsgInfo = getOptionalCsgInfo(); + cellIdentity.bands = BANDS; + + return cellIdentity; } @Test - public void testConvertHalCellInfoListForWcdma() { - android.hardware.radio.V1_0.CellInfoWcdma cellinfo = - new android.hardware.radio.V1_0.CellInfoWcdma(); - cellinfo.cellIdentityWcdma.lac = LAC; - cellinfo.cellIdentityWcdma.cid = CID; - cellinfo.cellIdentityWcdma.psc = PSC; - cellinfo.cellIdentityWcdma.uarfcn = UARFCN; - cellinfo.cellIdentityWcdma.mcc = MCC_STR; - cellinfo.cellIdentityWcdma.mnc = MNC_STR; - cellinfo.signalStrengthWcdma.signalStrength = RSSI_ASU; - cellinfo.signalStrengthWcdma.bitErrorRate = BIT_ERROR_RATE; - android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo(); - record.cellInfoType = TYPE_WCDMA; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.wcdma.add(cellinfo); + public void testConvertHalCellInfoList_1_5ForLte() { + android.hardware.radio.V1_5.CellInfoLte cellInfoLte = + new android.hardware.radio.V1_5.CellInfoLte(); + cellInfoLte.cellIdentityLte = getCellIdentityLte_1_5(); + cellInfoLte.signalStrengthLte = getLteSignalStrength_1_0(); + + android.hardware.radio.V1_5.CellInfo cellInfo = new android.hardware.radio.V1_5.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.lte(cellInfoLte); + ArrayList<Object> records = new ArrayList<>(); - records.add(record); + records.add(cellInfo); ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); - CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) ret.get(0); - CellInfoWcdma expected = new CellInfoWcdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityWcdma ci = new CellIdentityWcdma( - LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma( - RSSI, BIT_ERROR_RATE, Integer.MAX_VALUE, Integer.MAX_VALUE); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN); - cellInfoWcdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoWcdma); - } + CellInfoLte cil = (CellInfoLte) ret.get(0); + cil.setTimeStamp(TIMESTAMP); // override the timestamp - private static void initializeCellIdentityTdscdma_1_2( - android.hardware.radio.V1_2.CellIdentityTdscdma cid) { - cid.base.lac = LAC; - cid.base.cid = CID; - cid.base.cpid = PSC; - cid.base.mcc = MCC_STR; - cid.base.mnc = MNC_STR; - cid.uarfcn = UARFCN; - cid.operatorNames.alphaLong = ALPHA_LONG; - cid.operatorNames.alphaShort = ALPHA_SHORT; + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityLte cellIdentityLte = new CellIdentityLte(CI, PCI, TAC, EARFCN, + BANDS.stream().mapToInt(i -> i).toArray(), BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, + ALPHA_SHORT, additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthLte cellSignalStrengthLte = new CellSignalStrengthLte( + RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); + CellInfoLte expected = new CellInfoLte(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityLte, cellSignalStrengthLte, new CellConfigLte()); + assertEquals(expected, cil); } @Test - public void testConvertHalCellInfoListForTdscdma() { - android.hardware.radio.V1_2.CellInfoTdscdma cellinfo = - new android.hardware.radio.V1_2.CellInfoTdscdma(); - initializeCellIdentityTdscdma_1_2(cellinfo.cellIdentityTdscdma); - - cellinfo.signalStrengthTdscdma.signalStrength = RSSI_ASU; - cellinfo.signalStrengthTdscdma.bitErrorRate = BIT_ERROR_RATE; - cellinfo.signalStrengthTdscdma.rscp = RSCP_ASU; - android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_TD_SCDMA; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.tdscdma.add(cellinfo); + public void testConvertHalCellInfoList_1_6ForLte() { + android.hardware.radio.V1_6.LteSignalStrength signalStrength = + new android.hardware.radio.V1_6.LteSignalStrength(); + signalStrength.base = getLteSignalStrength_1_0(); + signalStrength.cqiTableIndex = CQI_TABLE_INDEX; + + android.hardware.radio.V1_6.CellInfoLte cellInfoLte = + new android.hardware.radio.V1_6.CellInfoLte(); + cellInfoLte.cellIdentityLte = getCellIdentityLte_1_5(); + cellInfoLte.signalStrengthLte = signalStrength; + + android.hardware.radio.V1_6.CellInfo cellInfo = new android.hardware.radio.V1_6.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.lte(cellInfoLte); + ArrayList<Object> records = new ArrayList<>(); - records.add(record); + records.add(cellInfo); ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); - CellInfoTdscdma cellInfoTdscdma = (CellInfoTdscdma) ret.get(0); - CellInfoTdscdma expected = new CellInfoTdscdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - CellIdentityTdscdma ci = new CellIdentityTdscdma( - MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthTdscdma cs = new CellSignalStrengthTdscdma( - RSSI, BIT_ERROR_RATE, RSCP); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - cellInfoTdscdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoTdscdma); + CellInfoLte cil = (CellInfoLte) ret.get(0); + cil.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityLte cellIdentityLte = new CellIdentityLte(CI, PCI, TAC, EARFCN, + BANDS.stream().mapToInt(i -> i).toArray(), BANDWIDTH, MCC_STR, MNC_STR, ALPHA_LONG, + ALPHA_SHORT, additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthLte cellSignalStrengthLte = new CellSignalStrengthLte( + RSSI, RSRP, RSRQ, RSSNR, CQI_TABLE_INDEX, CQI, TIMING_ADVANCE); + CellInfoLte expected = new CellInfoLte(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityLte, cellSignalStrengthLte, new CellConfigLte()); + assertEquals(expected, cil); } - @Test - public void testConvertHalCellInfoListForCdma() { - android.hardware.radio.V1_0.CellInfoCdma cellinfo = - new android.hardware.radio.V1_0.CellInfoCdma(); - cellinfo.cellIdentityCdma.networkId = NETWORK_ID; - cellinfo.cellIdentityCdma.systemId = SYSTEM_ID; - cellinfo.cellIdentityCdma.baseStationId = BASESTATION_ID; - cellinfo.cellIdentityCdma.longitude = LONGITUDE; - cellinfo.cellIdentityCdma.latitude = LATITUDE; - cellinfo.signalStrengthCdma.dbm = -DBM; - cellinfo.signalStrengthCdma.ecio = -ECIO; - cellinfo.signalStrengthEvdo.dbm = -DBM; - cellinfo.signalStrengthEvdo.ecio = -ECIO; - cellinfo.signalStrengthEvdo.signalNoiseRatio = SIGNAL_NOISE_RATIO; - android.hardware.radio.V1_0.CellInfo record = new android.hardware.radio.V1_0.CellInfo(); - record.cellInfoType = TYPE_CDMA; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.cdma.add(cellinfo); - ArrayList<Object> records = new ArrayList<>(); - records.add(record); + private android.hardware.radio.V1_2.CellIdentityGsm getCellIdentityGsm_1_2() { + android.hardware.radio.V1_0.CellIdentityGsm cellIdentity0 = + new android.hardware.radio.V1_0.CellIdentityGsm(); + cellIdentity0.mcc = MCC_STR; + cellIdentity0.mnc = MNC_STR; + cellIdentity0.lac = LAC; + cellIdentity0.cid = CID; + cellIdentity0.arfcn = ARFCN; + cellIdentity0.bsic = BSIC; - ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); + android.hardware.radio.V1_2.CellIdentityGsm cellIdentity = + new android.hardware.radio.V1_2.CellIdentityGsm(); + cellIdentity.base = cellIdentity0; + cellIdentity.operatorNames = getCellIdentityOperatorNames(); - assertEquals(1, ret.size()); - CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); - CellInfoCdma expected = new CellInfoCdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityCdma ci = new CellIdentityCdma( - NETWORK_ID, SYSTEM_ID, BASESTATION_ID, LONGITUDE, LATITUDE, - EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); - CellSignalStrengthCdma cs = new CellSignalStrengthCdma( - DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_UNKNOWN); - cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoCdma); + return cellIdentity; } - @Test - public void testConvertHalCellInfoList_1_2ForLTE() { - ArrayList<CellInfo> ret = getCellInfoListForLTE(MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT); + private android.hardware.radio.V1_0.GsmSignalStrength getGsmSignalStrength_1_0() { + android.hardware.radio.V1_0.GsmSignalStrength signalStrength = + new android.hardware.radio.V1_0.GsmSignalStrength(); + signalStrength.signalStrength = RSSI_ASU; + signalStrength.bitErrorRate = BIT_ERROR_RATE; + signalStrength.timingAdvance = TIMING_ADVANCE; - assertEquals(1, ret.size()); - CellInfoLte cellInfoLte = (CellInfoLte) ret.get(0); - CellInfoLte expected = new CellInfoLte(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityLte cil = new CellIdentityLte( - CI, PCI, TAC, EARFCN, new int[] {}, BANDWIDTH, MCC_STR, MNC_STR, - ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null); - CellSignalStrengthLte css = new CellSignalStrengthLte( - RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); - expected.setCellIdentity(cil); - expected.setCellSignalStrength(css); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoLte.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoLte); + return signalStrength; } @Test - public void testConvertHalCellInfoList_1_2_ForLTEWithEmptyOperatorInfo() { - ArrayList<CellInfo> ret = getCellInfoListForLTE( - MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); + public void testConvertHalCellInfoList_1_4ForGsm() { + android.hardware.radio.V1_2.CellInfoGsm cellInfoGsm = + new android.hardware.radio.V1_2.CellInfoGsm(); + cellInfoGsm.cellIdentityGsm = getCellIdentityGsm_1_2(); + cellInfoGsm.signalStrengthGsm = getGsmSignalStrength_1_0(); + + android.hardware.radio.V1_4.CellInfo cellInfo = new android.hardware.radio.V1_4.CellInfo(); + cellInfo.isRegistered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.info.gsm(cellInfoGsm); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); - CellInfoLte cellInfoLte = (CellInfoLte) ret.get(0); - CellInfoLte expected = new CellInfoLte(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityLte cil = new CellIdentityLte(CI, PCI, TAC, EARFCN, new int[] {}, - BANDWIDTH, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthLte css = new CellSignalStrengthLte( - RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); - expected.setCellIdentity(cil); - expected.setCellSignalStrength(css); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoLte.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoLte); + CellInfoGsm cig = (CellInfoGsm) ret.get(0); + cig.setTimeStamp(TIMESTAMP); // override the timestamp + + CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, Collections.emptyList()); + CellSignalStrengthGsm cellSignalStrengthGsm = new CellSignalStrengthGsm( + RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); + CellInfoGsm expected = new CellInfoGsm(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityGsm, cellSignalStrengthGsm); + assertEquals(expected, cig); } - @Test - public void testConvertHalCellInfoList_1_2ForLTEWithEmptyMccMnc() { - // MCC/MNC will be set as INT_MAX if unknown - ArrayList<CellInfo> ret = getCellInfoListForLTE( - String.valueOf(Integer.MAX_VALUE), String.valueOf(Integer.MAX_VALUE), - ALPHA_LONG, ALPHA_SHORT); + private android.hardware.radio.V1_5.CellInfoGsm getCellInfoGsm_1_5() { + android.hardware.radio.V1_5.CellIdentityGsm cellIdentity = + new android.hardware.radio.V1_5.CellIdentityGsm(); + cellIdentity.base = getCellIdentityGsm_1_2(); + cellIdentity.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); - assertEquals(1, ret.size()); - CellInfoLte cellInfoLte = (CellInfoLte) ret.get(0); - CellInfoLte expected = new CellInfoLte(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityLte cil = new CellIdentityLte( - CI, PCI, TAC, EARFCN, new int[] {}, BANDWIDTH, null, null, ALPHA_LONG, - ALPHA_SHORT, Collections.emptyList(), null); - CellSignalStrengthLte css = new CellSignalStrengthLte( - RSSI, RSRP, RSRQ, RSSNR, CQI, TIMING_ADVANCE); - expected.setCellIdentity(cil); - expected.setCellSignalStrength(css); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoLte.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoLte); + android.hardware.radio.V1_5.CellInfoGsm cellInfo = + new android.hardware.radio.V1_5.CellInfoGsm(); + cellInfo.cellIdentityGsm = cellIdentity; + cellInfo.signalStrengthGsm = getGsmSignalStrength_1_0(); + + return cellInfo; } @Test - public void testConvertHalCellInfoList_1_2ForGSM() { - ArrayList<CellInfo> ret = getCellInfoListForGSM(MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT); + public void testConvertHalCellInfoList_1_5ForGsm() { + android.hardware.radio.V1_5.CellInfo cellInfo = new android.hardware.radio.V1_5.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.gsm(getCellInfoGsm_1_5()); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); CellInfoGsm cellInfoGsm = (CellInfoGsm) ret.get(0); - CellInfoGsm expected = new CellInfoGsm(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityGsm ci = new CellIdentityGsm( - LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList()); - CellSignalStrengthGsm cs = new CellSignalStrengthGsm( - RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); cellInfoGsm.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, additionalPlmns); + CellSignalStrengthGsm cellSignalStrengthGsm = new CellSignalStrengthGsm( + RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); + CellInfoGsm expected = new CellInfoGsm(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityGsm, cellSignalStrengthGsm); assertEquals(expected, cellInfoGsm); } @Test - public void testConvertHalCellInfoList_1_2ForGSMWithEmptyOperatorInfo() { - ArrayList<CellInfo> ret = getCellInfoListForGSM( - MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); + public void testConvertHalCellInfoList_1_6ForGsm() { + android.hardware.radio.V1_6.CellInfo cellInfo = new android.hardware.radio.V1_6.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.gsm(getCellInfoGsm_1_5()); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); CellInfoGsm cellInfoGsm = (CellInfoGsm) ret.get(0); - CellInfoGsm expected = new CellInfoGsm(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityGsm ci = new CellIdentityGsm( - LAC, CID, ARFCN, BSIC, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList()); - CellSignalStrengthGsm cs = new CellSignalStrengthGsm( - RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); cellInfoGsm.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(LAC, CID, ARFCN, BSIC, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, additionalPlmns); + CellSignalStrengthGsm cellSignalStrengthGsm = new CellSignalStrengthGsm( + RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); + CellInfoGsm expected = new CellInfoGsm(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityGsm, cellSignalStrengthGsm); assertEquals(expected, cellInfoGsm); } - @Test - public void testConvertHalCellInfoList_1_2ForGSMWithEmptyMccMnc() { - // MCC/MNC will be set as INT_MAX if unknown - ArrayList<CellInfo> ret = getCellInfoListForGSM( - String.valueOf(Integer.MAX_VALUE), String.valueOf(Integer.MAX_VALUE), - ALPHA_LONG, ALPHA_SHORT); + private android.hardware.radio.V1_2.CellIdentityWcdma getCellIdentityWcdma_1_2() { + android.hardware.radio.V1_0.CellIdentityWcdma cellIdentity0 = + new android.hardware.radio.V1_0.CellIdentityWcdma(); + cellIdentity0.mcc = MCC_STR; + cellIdentity0.mnc = MNC_STR; + cellIdentity0.lac = LAC; + cellIdentity0.cid = CID; + cellIdentity0.psc = PSC; + cellIdentity0.uarfcn = UARFCN; - assertEquals(1, ret.size()); - CellInfoGsm cellInfoGsm = (CellInfoGsm) ret.get(0); - CellInfoGsm expected = new CellInfoGsm(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityGsm ci = new CellIdentityGsm( - LAC, CID, ARFCN, BSIC, null, null, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList()); - CellSignalStrengthGsm cs = new CellSignalStrengthGsm( - RSSI, BIT_ERROR_RATE, TIMING_ADVANCE); - expected.setCellIdentity(ci); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - expected.setCellSignalStrength(cs); - cellInfoGsm.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoGsm); + android.hardware.radio.V1_2.CellIdentityWcdma cellIdentity = + new android.hardware.radio.V1_2.CellIdentityWcdma(); + cellIdentity.base = cellIdentity0; + cellIdentity.operatorNames = getCellIdentityOperatorNames(); + + return cellIdentity; + } + + private android.hardware.radio.V1_2.WcdmaSignalStrength getWcdmaSignalStrength_1_2() { + android.hardware.radio.V1_0.WcdmaSignalStrength signalStrength0 = + new android.hardware.radio.V1_0.WcdmaSignalStrength(); + signalStrength0.signalStrength = RSSI_ASU; + signalStrength0.bitErrorRate = BIT_ERROR_RATE; + + android.hardware.radio.V1_2.WcdmaSignalStrength signalStrength = + new android.hardware.radio.V1_2.WcdmaSignalStrength(); + signalStrength.base = signalStrength0; + signalStrength.rscp = RSCP_ASU; + signalStrength.ecno = ECNO_ASU; + + return signalStrength; } @Test - public void testConvertHalCellInfoList_1_2ForWcdma() { - ArrayList<CellInfo> ret = getCellInfoListForWcdma( - MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT); + public void testConvertHalCellInfoList_1_4ForWcdma() { + android.hardware.radio.V1_2.CellInfoWcdma cellInfoWcdma = + new android.hardware.radio.V1_2.CellInfoWcdma(); + cellInfoWcdma.cellIdentityWcdma = getCellIdentityWcdma_1_2(); + cellInfoWcdma.signalStrengthWcdma = getWcdmaSignalStrength_1_2(); + + android.hardware.radio.V1_4.CellInfo cellInfo = new android.hardware.radio.V1_4.CellInfo(); + cellInfo.isRegistered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.info.wcdma(cellInfoWcdma); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); - CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) ret.get(0); - CellInfoWcdma expected = new CellInfoWcdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityWcdma ci = new CellIdentityWcdma( - LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthWcdma cs = - new CellSignalStrengthWcdma(RSSI, BIT_ERROR_RATE, RSCP, ECNO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoWcdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoWcdma); + CellInfoWcdma ciw = (CellInfoWcdma) ret.get(0); + ciw.setTimeStamp(TIMESTAMP); // override the timestamp + + CellIdentityWcdma cellIdentityWcdma = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, Collections.emptyList(), null); + CellSignalStrengthWcdma cellSignalStrengthWcdma = new CellSignalStrengthWcdma( + RSSI, BIT_ERROR_RATE, RSCP, ECNO); + CellInfoWcdma expected = new CellInfoWcdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityWcdma, cellSignalStrengthWcdma); + assertEquals(expected, ciw); + } + + private android.hardware.radio.V1_5.CellInfoWcdma getCellInfoWcdma_1_5() { + android.hardware.radio.V1_5.CellIdentityWcdma cellIdentity = + new android.hardware.radio.V1_5.CellIdentityWcdma(); + cellIdentity.base = getCellIdentityWcdma_1_2(); + cellIdentity.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); + cellIdentity.optionalCsgInfo = getOptionalCsgInfo(); + + android.hardware.radio.V1_5.CellInfoWcdma cellInfo = + new android.hardware.radio.V1_5.CellInfoWcdma(); + cellInfo.cellIdentityWcdma = cellIdentity; + cellInfo.signalStrengthWcdma = getWcdmaSignalStrength_1_2(); + + return cellInfo; } @Test - public void testConvertHalCellInfoList_1_2ForWcdmaWithEmptyOperatorInfo() { - ArrayList<CellInfo> ret = getCellInfoListForWcdma( - MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); + public void testConvertHalCellInfoList_1_5ForWcdma() { + android.hardware.radio.V1_5.CellInfo cellInfo = new android.hardware.radio.V1_5.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.wcdma(getCellInfoWcdma_1_5()); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) ret.get(0); - CellInfoWcdma expected = new CellInfoWcdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityWcdma ci = new CellIdentityWcdma( - LAC, CID, PSC, UARFCN, MCC_STR, MNC_STR, EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma( - RSSI, BIT_ERROR_RATE, RSCP, ECNO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); cellInfoWcdma.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityWcdma cellIdentityWcdma = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthWcdma cellSignalStrengthWcdma = new CellSignalStrengthWcdma( + RSSI, BIT_ERROR_RATE, RSCP, ECNO); + CellInfoWcdma expected = new CellInfoWcdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityWcdma, cellSignalStrengthWcdma); assertEquals(expected, cellInfoWcdma); } @Test - public void testConvertHalCellInfoList_1_2ForWcdmaWithEmptyMccMnc() { - // MCC/MNC will be set as INT_MAX if unknown - ArrayList<CellInfo> ret = getCellInfoListForWcdma(null, null, ALPHA_LONG, ALPHA_SHORT); + public void testConvertHalCellInfoList_1_6ForWcdma() { + android.hardware.radio.V1_6.CellInfo cellInfo = new android.hardware.radio.V1_6.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.wcdma(getCellInfoWcdma_1_5()); + + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); assertEquals(1, ret.size()); CellInfoWcdma cellInfoWcdma = (CellInfoWcdma) ret.get(0); - CellInfoWcdma expected = new CellInfoWcdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityWcdma ci = new CellIdentityWcdma( - LAC, CID, PSC, UARFCN, null, null, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList(), null); - CellSignalStrengthWcdma cs = new CellSignalStrengthWcdma( - RSSI, BIT_ERROR_RATE, RSCP, ECNO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); cellInfoWcdma.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityWcdma cellIdentityWcdma = new CellIdentityWcdma(LAC, CID, PSC, UARFCN, MCC_STR, + MNC_STR, ALPHA_LONG, ALPHA_SHORT, additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthWcdma cellSignalStrengthWcdma = new CellSignalStrengthWcdma( + RSSI, BIT_ERROR_RATE, RSCP, ECNO); + CellInfoWcdma expected = new CellInfoWcdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityWcdma, cellSignalStrengthWcdma); assertEquals(expected, cellInfoWcdma); } - @Test - public void testConvertHalCellInfoList_1_2ForCdma() { - ArrayList<CellInfo> ret = getCellInfoListForCdma(ALPHA_LONG, ALPHA_SHORT); + private android.hardware.radio.V1_2.CellIdentityTdscdma getCellIdentityTdscdma_1_2() { + android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentity0 = + new android.hardware.radio.V1_0.CellIdentityTdscdma(); + cellIdentity0.mcc = MCC_STR; + cellIdentity0.mnc = MNC_STR; + cellIdentity0.lac = LAC; + cellIdentity0.cid = CID; + cellIdentity0.cpid = PSC; - assertEquals(1, ret.size()); - CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); - CellInfoCdma expected = new CellInfoCdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityCdma ci = new CellIdentityCdma( - NETWORK_ID, SYSTEM_ID, BASESTATION_ID, LONGITUDE, LATITUDE, - ALPHA_LONG, ALPHA_SHORT); - CellSignalStrengthCdma cs = new CellSignalStrengthCdma( - DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoCdma); + android.hardware.radio.V1_2.CellIdentityTdscdma cellIdentity = + new android.hardware.radio.V1_2.CellIdentityTdscdma(); + cellIdentity.base = cellIdentity0; + cellIdentity.uarfcn = UARFCN; + cellIdentity.operatorNames = getCellIdentityOperatorNames(); + + return cellIdentity; } - @Test - public void testConvertHalCellInfoList_1_2ForCdmaWithEmptyOperatorInfo() { - ArrayList<CellInfo> ret = getCellInfoListForCdma(EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); + private android.hardware.radio.V1_2.TdscdmaSignalStrength getTdscdmaSignalStrength_1_2() { + android.hardware.radio.V1_2.TdscdmaSignalStrength signalStrength = + new android.hardware.radio.V1_2.TdscdmaSignalStrength(); + signalStrength.signalStrength = RSSI_ASU; + signalStrength.bitErrorRate = BIT_ERROR_RATE; + signalStrength.rscp = RSCP_ASU; - assertEquals(1, ret.size()); - CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); - CellInfoCdma expected = new CellInfoCdma(); - expected.setRegistered(false); - expected.setTimeStamp(TIMESTAMP); - CellIdentityCdma ci = new CellIdentityCdma( - NETWORK_ID, SYSTEM_ID, BASESTATION_ID, LONGITUDE, LATITUDE, - EMPTY_ALPHA_LONG, EMPTY_ALPHA_SHORT); - CellSignalStrengthCdma cs = new CellSignalStrengthCdma( - DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); - expected.setCellIdentity(ci); - expected.setCellSignalStrength(cs); - expected.setCellConnectionStatus(CellInfo.CONNECTION_NONE); - cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expected, cellInfoCdma); + return signalStrength; } @Test - public void testConvertHalCellInfoList_1_4ForNr() { - android.hardware.radio.V1_4.CellInfoNr cellinfo = - new android.hardware.radio.V1_4.CellInfoNr(); - cellinfo.cellidentity.nci = CI; - cellinfo.cellidentity.pci = PCI; - cellinfo.cellidentity.tac = TAC; - cellinfo.cellidentity.nrarfcn = NRARFCN; - cellinfo.cellidentity.mcc = MCC_STR; - cellinfo.cellidentity.mnc = MNC_STR; - cellinfo.cellidentity.operatorNames.alphaLong = ALPHA_LONG; - cellinfo.cellidentity.operatorNames.alphaShort = ALPHA_SHORT; - cellinfo.signalStrength.ssRsrp = RSRP; - cellinfo.signalStrength.ssRsrq = RSRQ; - cellinfo.signalStrength.ssSinr = SIGNAL_NOISE_RATIO; - cellinfo.signalStrength.csiRsrp = RSRP; - cellinfo.signalStrength.csiRsrq = RSRQ; - cellinfo.signalStrength.csiSinr = SIGNAL_NOISE_RATIO; + public void testConvertHalCellInfoList_1_4ForTdscdma() { + android.hardware.radio.V1_2.CellInfoTdscdma cellInfoTdscdma = + new android.hardware.radio.V1_2.CellInfoTdscdma(); + cellInfoTdscdma.cellIdentityTdscdma = getCellIdentityTdscdma_1_2(); + cellInfoTdscdma.signalStrengthTdscdma = getTdscdmaSignalStrength_1_2(); - android.hardware.radio.V1_4.CellInfo record = new android.hardware.radio.V1_4.CellInfo(); - record.info.nr(cellinfo); + android.hardware.radio.V1_4.CellInfo cellInfo = new android.hardware.radio.V1_4.CellInfo(); + cellInfo.isRegistered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.info.tdscdma(cellInfoTdscdma); ArrayList<Object> records = new ArrayList<>(); - records.add(record); + records.add(cellInfo); ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - CellInfoNr cellInfoNr = (CellInfoNr) ret.get(0); - CellIdentityNr cellIdentityNr = (CellIdentityNr) cellInfoNr.getCellIdentity(); - CellSignalStrengthNr signalStrengthNr = - (CellSignalStrengthNr) cellInfoNr.getCellSignalStrength(); - - CellIdentityNr expectedCellIdentity = new CellIdentityNr(PCI, TAC, NRARFCN, - new int[] {}, MCC_STR, MNC_STR, CI, ALPHA_LONG, ALPHA_SHORT, - Collections.emptyList()); - CellSignalStrengthNr expectedSignalStrength = new CellSignalStrengthNr(-RSRP, -RSRQ, - SIGNAL_NOISE_RATIO, -RSRP, -RSRQ, SIGNAL_NOISE_RATIO); + assertEquals(1, ret.size()); + CellInfoTdscdma cit = (CellInfoTdscdma) ret.get(0); + cit.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(expectedCellIdentity, cellIdentityNr); - assertEquals(expectedSignalStrength, signalStrengthNr); + CellIdentityTdscdma cellIdentityTdscdma = new CellIdentityTdscdma( + MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, ALPHA_LONG, ALPHA_SHORT, + Collections.emptyList(), null); + CellSignalStrengthTdscdma cellSignalStrengthTdscdma = new CellSignalStrengthTdscdma( + RSSI, BIT_ERROR_RATE, RSCP); + CellInfoTdscdma expected = new CellInfoTdscdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityTdscdma, cellSignalStrengthTdscdma); + assertEquals(expected, cit); } - private static android.hardware.radio.V1_5.ClosedSubscriberGroupInfo getHalCsgInfo() { - android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo = - new android.hardware.radio.V1_5.ClosedSubscriberGroupInfo(); + private android.hardware.radio.V1_5.CellInfoTdscdma getCellInfoTdscdma_1_5() { + android.hardware.radio.V1_5.CellIdentityTdscdma cellIdentity = + new android.hardware.radio.V1_5.CellIdentityTdscdma(); + cellIdentity.base = getCellIdentityTdscdma_1_2(); + cellIdentity.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); + cellIdentity.optionalCsgInfo = getOptionalCsgInfo(); - csgInfo.csgIndication = CSG_INDICATION; - csgInfo.homeNodebName = HOME_NODEB_NAME; - csgInfo.csgIdentity = CSG_IDENTITY; + android.hardware.radio.V1_5.CellInfoTdscdma cellInfo = + new android.hardware.radio.V1_5.CellInfoTdscdma(); + cellInfo.cellIdentityTdscdma = cellIdentity; + cellInfo.signalStrengthTdscdma = getTdscdmaSignalStrength_1_2(); - return csgInfo; + return cellInfo; } - private static void initializeCellIdentityLte_1_5( - android.hardware.radio.V1_5.CellIdentityLte id, - boolean addAdditionalPlmns, boolean addCsgInfo) { + @Test + public void testConvertHalCellInfoList_1_5ForTdscdma() { + android.hardware.radio.V1_5.CellInfo cellInfo = new android.hardware.radio.V1_5.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.tdscdma(getCellInfoTdscdma_1_5()); - initializeCellIdentityLte_1_2(id.base); + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); - if (addAdditionalPlmns) { - id.additionalPlmns = new ArrayList<>( - Arrays.asList(ADDITIONAL_PLMNS)); - } + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - if (addCsgInfo) { - id.optionalCsgInfo.csgInfo(getHalCsgInfo()); - } + assertEquals(1, ret.size()); + CellInfoTdscdma cellInfoTdscdma = (CellInfoTdscdma) ret.get(0); + cellInfoTdscdma.setTimeStamp(TIMESTAMP); // override the timestamp + + Set<String> additionalPlmns = new HashSet<>(); + Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityTdscdma cellIdentityTdscdma = new CellIdentityTdscdma( + MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, ALPHA_LONG, ALPHA_SHORT, + additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthTdscdma cellSignalStrengthTdscdma = new CellSignalStrengthTdscdma( + RSSI, BIT_ERROR_RATE, RSCP); + CellInfoTdscdma expected = new CellInfoTdscdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityTdscdma, cellSignalStrengthTdscdma); + assertEquals(expected, cellInfoTdscdma); } @Test - public void testCellIdentityLte_1_5_CsgInfo() { - android.hardware.radio.V1_5.CellIdentityLte halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityLte(); - initializeCellIdentityLte_1_5(halCellIdentity, false, true); + public void testConvertHalCellInfoList_1_6ForTdscdma() { + android.hardware.radio.V1_6.CellInfo cellInfo = new android.hardware.radio.V1_6.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.tdscdma(getCellInfoTdscdma_1_5()); - CellIdentityLte cellIdentity = RILUtils.convertHalCellIdentityLte(halCellIdentity); - - assertEquals(CSG_INDICATION, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator()); - assertEquals(HOME_NODEB_NAME, - cellIdentity.getClosedSubscriberGroupInfo().getHomeNodebName()); - assertEquals(CSG_IDENTITY, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIdentity()); - } + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); - @Test - public void testCellIdentityLte_1_5_MultiPlmn() { - android.hardware.radio.V1_5.CellIdentityLte halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityLte(); - initializeCellIdentityLte_1_5(halCellIdentity, true, false); + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - CellIdentityLte cellIdentity = RILUtils.convertHalCellIdentityLte(halCellIdentity); + assertEquals(1, ret.size()); + CellInfoTdscdma cellInfoTdscdma = (CellInfoTdscdma) ret.get(0); + cellInfoTdscdma.setTimeStamp(TIMESTAMP); // override the timestamp Set<String> additionalPlmns = new HashSet<>(); Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); - - assertEquals(cellIdentity.getAdditionalPlmns(), additionalPlmns); + ClosedSubscriberGroupInfo closedSubscriberGroupInfo = + new ClosedSubscriberGroupInfo(CSG_INDICATION, HOME_NODEB_NAME, CSG_IDENTITY); + CellIdentityTdscdma cellIdentityTdscdma = new CellIdentityTdscdma( + MCC_STR, MNC_STR, LAC, CID, PSC, UARFCN, ALPHA_LONG, ALPHA_SHORT, + additionalPlmns, closedSubscriberGroupInfo); + CellSignalStrengthTdscdma cellSignalStrengthTdscdma = new CellSignalStrengthTdscdma( + RSSI, BIT_ERROR_RATE, RSCP); + CellInfoTdscdma expected = new CellInfoTdscdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityTdscdma, cellSignalStrengthTdscdma); + assertEquals(expected, cellInfoTdscdma); } - private static void initializeCellIdentityWcdma_1_5( - android.hardware.radio.V1_5.CellIdentityWcdma id, - boolean addAdditionalPlmns, boolean addCsgInfo) { - - initializeCellIdentityWcdma_1_2(id.base); - - if (addAdditionalPlmns) { - id.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); - } + private android.hardware.radio.V1_2.CellInfoCdma getCellInfoCdma_1_2() { + android.hardware.radio.V1_0.CellIdentityCdma cellIdentity0 = + new android.hardware.radio.V1_0.CellIdentityCdma(); + cellIdentity0.networkId = NETWORK_ID; + cellIdentity0.systemId = SYSTEM_ID; + cellIdentity0.baseStationId = BASESTATION_ID; + cellIdentity0.longitude = LONGITUDE; + cellIdentity0.latitude = LATITUDE; + + android.hardware.radio.V1_2.CellIdentityCdma cellIdentity = + new android.hardware.radio.V1_2.CellIdentityCdma(); + cellIdentity.base = cellIdentity0; + cellIdentity.operatorNames = getCellIdentityOperatorNames(); + + android.hardware.radio.V1_0.CdmaSignalStrength cdmaSignalStrength = + new android.hardware.radio.V1_0.CdmaSignalStrength(); + cdmaSignalStrength.dbm = -DBM; + cdmaSignalStrength.ecio = -ECIO; + + android.hardware.radio.V1_0.EvdoSignalStrength evdoSignalStrength = + new android.hardware.radio.V1_0.EvdoSignalStrength(); + evdoSignalStrength.dbm = -DBM; + evdoSignalStrength.ecio = -ECIO; + evdoSignalStrength.signalNoiseRatio = SIGNAL_NOISE_RATIO; + + android.hardware.radio.V1_2.CellInfoCdma cellInfo = + new android.hardware.radio.V1_2.CellInfoCdma(); + cellInfo.cellIdentityCdma = cellIdentity; + cellInfo.signalStrengthCdma = cdmaSignalStrength; + cellInfo.signalStrengthEvdo = evdoSignalStrength; - if (addCsgInfo) { - id.optionalCsgInfo.csgInfo(getHalCsgInfo()); - } + return cellInfo; } @Test - public void testCellIdentityWcdma_1_5_CsgInfo() { - android.hardware.radio.V1_5.CellIdentityWcdma halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityWcdma(); - initializeCellIdentityWcdma_1_5(halCellIdentity, false, true); + public void testConvertHalCellInfoList_1_4ForCdma() { + android.hardware.radio.V1_4.CellInfo cellInfo = new android.hardware.radio.V1_4.CellInfo(); + cellInfo.isRegistered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.info.cdma(getCellInfoCdma_1_2()); - CellIdentityWcdma cellIdentity = RILUtils.convertHalCellIdentityWcdma(halCellIdentity); + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); + + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - assertEquals(CSG_INDICATION, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator()); - assertEquals(HOME_NODEB_NAME, - cellIdentity.getClosedSubscriberGroupInfo().getHomeNodebName()); - assertEquals(CSG_IDENTITY, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIdentity()); + assertEquals(1, ret.size()); + CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); + cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp + + CellIdentityCdma cellIdentityCdma = new CellIdentityCdma(NETWORK_ID, SYSTEM_ID, + BASESTATION_ID, LONGITUDE, LATITUDE, ALPHA_LONG, ALPHA_SHORT); + CellSignalStrengthCdma cellSignalStrengthCdma = new CellSignalStrengthCdma( + DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); + CellInfoCdma expected = new CellInfoCdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityCdma, cellSignalStrengthCdma); + assertEquals(expected, cellInfoCdma); } @Test - public void testCellIdentityWcdma_1_5_MultiPlmn() { - android.hardware.radio.V1_5.CellIdentityWcdma halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityWcdma(); - initializeCellIdentityWcdma_1_5(halCellIdentity, true, false); + public void testConvertHalCellInfoList_1_5ForCdma() { + android.hardware.radio.V1_5.CellInfo cellInfo = new android.hardware.radio.V1_5.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.cdma(getCellInfoCdma_1_2()); - CellIdentityWcdma cellIdentity = RILUtils.convertHalCellIdentityWcdma(halCellIdentity); + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); - Set<String> additionalPlmns = new HashSet<>(); - Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); + + assertEquals(1, ret.size()); + CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); + cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp - assertEquals(cellIdentity.getAdditionalPlmns(), additionalPlmns); + CellIdentityCdma cellIdentityCdma = new CellIdentityCdma(NETWORK_ID, SYSTEM_ID, + BASESTATION_ID, LONGITUDE, LATITUDE, ALPHA_LONG, ALPHA_SHORT); + CellSignalStrengthCdma cellSignalStrengthCdma = new CellSignalStrengthCdma( + DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); + CellInfoCdma expected = new CellInfoCdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityCdma, cellSignalStrengthCdma); + assertEquals(expected, cellInfoCdma); } - private static void initializeCellIdentityTdscdma_1_5( - android.hardware.radio.V1_5.CellIdentityTdscdma id, - boolean addAdditionalPlmns, boolean addCsgInfo) { + @Test + public void testConvertHalCellInfoList_1_6ForCdma() { + android.hardware.radio.V1_6.CellInfo cellInfo = new android.hardware.radio.V1_6.CellInfo(); + cellInfo.registered = REGISTERED; + cellInfo.connectionStatus = CONNECTION_STATUS; + cellInfo.ratSpecificInfo.cdma(getCellInfoCdma_1_2()); - initializeCellIdentityTdscdma_1_2(id.base); + ArrayList<Object> records = new ArrayList<>(); + records.add(cellInfo); - if (addAdditionalPlmns) { - id.additionalPlmns = new ArrayList<>(Arrays.asList(ADDITIONAL_PLMNS)); - } + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - if (addCsgInfo) { - id.optionalCsgInfo.csgInfo(getHalCsgInfo()); - } + assertEquals(1, ret.size()); + CellInfoCdma cellInfoCdma = (CellInfoCdma) ret.get(0); + cellInfoCdma.setTimeStamp(TIMESTAMP); // override the timestamp + + CellIdentityCdma cellIdentityCdma = new CellIdentityCdma(NETWORK_ID, SYSTEM_ID, + BASESTATION_ID, LONGITUDE, LATITUDE, ALPHA_LONG, ALPHA_SHORT); + CellSignalStrengthCdma cellSignalStrengthCdma = new CellSignalStrengthCdma( + DBM, ECIO, DBM, ECIO, SIGNAL_NOISE_RATIO); + CellInfoCdma expected = new CellInfoCdma(CONNECTION_STATUS, REGISTERED, TIMESTAMP, + cellIdentityCdma, cellSignalStrengthCdma); + assertEquals(expected, cellInfoCdma); } @Test - public void testCellIdentityTdscdma_1_5_CsgInfo() { - android.hardware.radio.V1_5.CellIdentityTdscdma halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityTdscdma(); - initializeCellIdentityTdscdma_1_5(halCellIdentity, false, true); + public void testConvertHalCellInfoList_1_4ForNr() { + android.hardware.radio.V1_4.CellInfoNr cellinfo = + new android.hardware.radio.V1_4.CellInfoNr(); + cellinfo.cellidentity.nci = CI; + cellinfo.cellidentity.pci = PCI; + cellinfo.cellidentity.tac = TAC; + cellinfo.cellidentity.nrarfcn = NRARFCN; + cellinfo.cellidentity.mcc = MCC_STR; + cellinfo.cellidentity.mnc = MNC_STR; + cellinfo.cellidentity.operatorNames.alphaLong = ALPHA_LONG; + cellinfo.cellidentity.operatorNames.alphaShort = ALPHA_SHORT; + cellinfo.signalStrength.ssRsrp = RSRP; + cellinfo.signalStrength.ssRsrq = RSRQ; + cellinfo.signalStrength.ssSinr = SIGNAL_NOISE_RATIO; + cellinfo.signalStrength.csiRsrp = RSRP; + cellinfo.signalStrength.csiRsrq = RSRQ; + cellinfo.signalStrength.csiSinr = SIGNAL_NOISE_RATIO; - CellIdentityTdscdma cellIdentity = RILUtils.convertHalCellIdentityTdscdma(halCellIdentity); + android.hardware.radio.V1_4.CellInfo record = new android.hardware.radio.V1_4.CellInfo(); + record.info.nr(cellinfo); - assertEquals(CSG_INDICATION, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIndicator()); - assertEquals(HOME_NODEB_NAME, - cellIdentity.getClosedSubscriberGroupInfo().getHomeNodebName()); - assertEquals(CSG_IDENTITY, - cellIdentity.getClosedSubscriberGroupInfo().getCsgIdentity()); - } + ArrayList<Object> records = new ArrayList<>(); + records.add(record); - @Test - public void testCellIdentityTdscdma_1_5_MultiPlmn() { - android.hardware.radio.V1_5.CellIdentityTdscdma halCellIdentity = - new android.hardware.radio.V1_5.CellIdentityTdscdma(); - initializeCellIdentityTdscdma_1_5(halCellIdentity, true, false); + ArrayList<CellInfo> ret = RILUtils.convertHalCellInfoList(records); - CellIdentityTdscdma cellIdentity = RILUtils.convertHalCellIdentityTdscdma(halCellIdentity); + CellInfoNr cellInfoNr = (CellInfoNr) ret.get(0); + CellIdentityNr cellIdentityNr = (CellIdentityNr) cellInfoNr.getCellIdentity(); + CellSignalStrengthNr signalStrengthNr = + (CellSignalStrengthNr) cellInfoNr.getCellSignalStrength(); - Set<String> additionalPlmns = new HashSet<>(); - Collections.addAll(additionalPlmns, ADDITIONAL_PLMNS); + CellIdentityNr expectedCellIdentity = new CellIdentityNr(PCI, TAC, NRARFCN, + new int[] {}, MCC_STR, MNC_STR, CI, ALPHA_LONG, ALPHA_SHORT, + Collections.emptyList()); + CellSignalStrengthNr expectedSignalStrength = new CellSignalStrengthNr(-RSRP, -RSRQ, + SIGNAL_NOISE_RATIO, -RSRP, -RSRQ, SIGNAL_NOISE_RATIO); - assertEquals(cellIdentity.getAdditionalPlmns(), additionalPlmns); + assertEquals(expectedCellIdentity, cellIdentityNr); + assertEquals(expectedSignalStrength, signalStrengthNr); } @Test public void testConvertDataCallResult() { - // Test V1.0 SetupDataCallResult - android.hardware.radio.V1_0.SetupDataCallResult result10 = - new android.hardware.radio.V1_0.SetupDataCallResult(); - result10.status = android.hardware.radio.V1_0.DataCallFailCause.NONE; - result10.suggestedRetryTime = -1; - result10.cid = 0; - result10.active = 2; - result10.type = "IPV4V6"; - result10.ifname = "ifname"; - result10.addresses = "10.0.2.15 2607:fb90:a620:651d:eabe:f8da:c107:44be/64"; - result10.dnses = "10.0.2.3 fd00:976a::9"; - result10.gateways = "10.0.2.15 fe80::2"; - result10.pcscf = "fd00:976a:c206:20::6 fd00:976a:c206:20::9 fd00:976a:c202:1d::9"; - result10.mtu = 1500; - DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) @@ -2294,8 +2305,6 @@ public class RILTest extends TelephonyTest { .setTrafficDescriptors(new ArrayList<>()) .build(); - assertEquals(response, RILUtils.convertHalDataCallResult(result10)); - // Test V1.4 SetupDataCallResult android.hardware.radio.V1_4.SetupDataCallResult result14 = new android.hardware.radio.V1_4.SetupDataCallResult(); @@ -2532,11 +2541,7 @@ public class RILTest extends TelephonyTest { ArrayList<Object> records = new ArrayList<>(); for (int i = 0; i < 5 /* arbitrary */; i++) { - android.hardware.radio.V1_4.CellInfo record = - new android.hardware.radio.V1_4.CellInfo(); - record.info = new android.hardware.radio.V1_4.CellInfo.Info(); - record.info.lte(new android.hardware.radio.V1_4.CellInfoLte()); - initializeCellInfoLte_1_2(record.info.lte().base); + android.hardware.radio.V1_4.CellInfo record = getCellInfo_1_4ForLte(); record.info.lte().base.cellIdentityLte.base.ci += i; // make them marginally unique records.add(record); @@ -2552,181 +2557,6 @@ public class RILTest extends TelephonyTest { } @Test - public void testCellInfoTimestamp_1_2() { - ArrayList<Object> records = new ArrayList<>(); - - for (int i = 0; i < 5 /* arbitrary */; i++) { - android.hardware.radio.V1_2.CellInfo record = - new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_LTE; - record.timeStamp = Long.MAX_VALUE; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.lte.add(new android.hardware.radio.V1_2.CellInfoLte()); - initializeCellInfoLte_1_2(record.lte.get(0)); - record.lte.get(0).cellIdentityLte.base.ci += i; // make them marginally unique - - records.add(record); - } - List<CellInfo> cil = RILUtils.convertHalCellInfoList(records); - - // Check that all timestamps are set to a valid number and are equal - final long ts = cil.get(0).getTimeStamp(); - for (CellInfo ci : cil) { - assertTrue(ci.getTimeStamp() > 0 && ci.getTimeStamp() != Long.MAX_VALUE); - assertEquals(ci.getTimeStamp(), ts); - } - } - - private static void initializeCellIdentityLte_1_2( - android.hardware.radio.V1_2.CellIdentityLte id) { - // 1.0 fields - id.base.mcc = MCC_STR; - id.base.mnc = MNC_STR; - id.base.ci = CI; - id.base.pci = PCI; - id.base.tac = TAC; - id.base.earfcn = EARFCN; - - // 1.2 fields - id.bandwidth = BANDWIDTH; - id.operatorNames.alphaLong = ALPHA_LONG; - id.operatorNames.alphaShort = ALPHA_SHORT; - } - - private static void initializeCellInfoLte_1_2(android.hardware.radio.V1_2.CellInfoLte lte) { - initializeCellIdentityLte_1_2(lte.cellIdentityLte); - - lte.signalStrengthLte.signalStrength = RSSI_ASU; - lte.signalStrengthLte.rsrp = -RSRP; - lte.signalStrengthLte.rsrq = -RSRQ; - lte.signalStrengthLte.rssnr = RSSNR; - lte.signalStrengthLte.cqi = CQI; - lte.signalStrengthLte.timingAdvance = TIMING_ADVANCE; - } - - private ArrayList<CellInfo> getCellInfoListForLTE( - String mcc, String mnc, String alphaLong, String alphaShort) { - android.hardware.radio.V1_2.CellInfoLte lte = new android.hardware.radio.V1_2.CellInfoLte(); - - initializeCellInfoLte_1_2(lte); - // Override the defaults for test-specific purposes - lte.cellIdentityLte.operatorNames.alphaLong = alphaLong; - lte.cellIdentityLte.operatorNames.alphaShort = alphaShort; - lte.cellIdentityLte.base.mcc = mcc; - lte.cellIdentityLte.base.mnc = mnc; - - android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_LTE; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.lte.add(lte); - record.connectionStatus = 0; - ArrayList<Object> records = new ArrayList<>(); - records.add(record); - return RILUtils.convertHalCellInfoList(records); - } - - private ArrayList<CellInfo> getCellInfoListForGSM( - String mcc, String mnc, String alphaLong, String alphaShort) { - android.hardware.radio.V1_2.CellInfoGsm cellinfo = - new android.hardware.radio.V1_2.CellInfoGsm(); - cellinfo.cellIdentityGsm.base.lac = LAC; - cellinfo.cellIdentityGsm.base.cid = CID; - cellinfo.cellIdentityGsm.base.bsic = BSIC; - cellinfo.cellIdentityGsm.base.arfcn = ARFCN; - cellinfo.cellIdentityGsm.base.mcc = mcc; - cellinfo.cellIdentityGsm.base.mnc = mnc; - cellinfo.cellIdentityGsm.operatorNames.alphaLong = alphaLong; - cellinfo.cellIdentityGsm.operatorNames.alphaShort = alphaShort; - cellinfo.signalStrengthGsm.signalStrength = RSSI_ASU; - cellinfo.signalStrengthGsm.bitErrorRate = BIT_ERROR_RATE; - cellinfo.signalStrengthGsm.timingAdvance = TIMING_ADVANCE; - android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_GSM; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.gsm.add(cellinfo); - record.connectionStatus = 0; - ArrayList<Object> records = new ArrayList<>(); - records.add(record); - - return RILUtils.convertHalCellInfoList(records); - } - - private static void initializeCellIdentityWcdma_1_2( - android.hardware.radio.V1_2.CellIdentityWcdma cid) { - initializeCellIdentityWcdma_1_2(cid, MCC_STR, MNC_STR, ALPHA_LONG, ALPHA_SHORT); - } - - private static void initializeCellIdentityWcdma_1_2( - android.hardware.radio.V1_2.CellIdentityWcdma cid, - String mcc, String mnc, String alphaLong, String alphaShort) { - cid.base.lac = LAC; - cid.base.cid = CID; - cid.base.psc = PSC; - cid.base.uarfcn = UARFCN; - cid.base.mcc = mcc; - cid.base.mnc = mnc; - cid.operatorNames.alphaLong = alphaLong; - cid.operatorNames.alphaShort = alphaShort; - } - - private ArrayList<CellInfo> getCellInfoListForWcdma( - String mcc, String mnc, String alphaLong, String alphaShort) { - android.hardware.radio.V1_2.CellInfoWcdma cellinfo = - new android.hardware.radio.V1_2.CellInfoWcdma(); - initializeCellIdentityWcdma_1_2( - cellinfo.cellIdentityWcdma, mcc, mnc, alphaLong, alphaShort); - - cellinfo.signalStrengthWcdma.base.signalStrength = RSSI_ASU; - cellinfo.signalStrengthWcdma.base.bitErrorRate = BIT_ERROR_RATE; - cellinfo.signalStrengthWcdma.rscp = RSCP_ASU; - cellinfo.signalStrengthWcdma.ecno = ECNO_ASU; - android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_WCDMA; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.wcdma.add(cellinfo); - record.connectionStatus = 0; - ArrayList<Object> records = new ArrayList<>(); - records.add(record); - - return RILUtils.convertHalCellInfoList(records); - } - - private ArrayList<CellInfo> getCellInfoListForCdma(String alphaLong, String alphaShort) { - android.hardware.radio.V1_2.CellInfoCdma cellinfo = - new android.hardware.radio.V1_2.CellInfoCdma(); - cellinfo.cellIdentityCdma.base.networkId = NETWORK_ID; - cellinfo.cellIdentityCdma.base.systemId = SYSTEM_ID; - cellinfo.cellIdentityCdma.base.baseStationId = BASESTATION_ID; - cellinfo.cellIdentityCdma.base.longitude = LONGITUDE; - cellinfo.cellIdentityCdma.base.latitude = LATITUDE; - cellinfo.cellIdentityCdma.operatorNames.alphaLong = alphaLong; - cellinfo.cellIdentityCdma.operatorNames.alphaShort = alphaShort; - cellinfo.signalStrengthCdma.dbm = -DBM; - cellinfo.signalStrengthCdma.ecio = -ECIO; - cellinfo.signalStrengthEvdo.dbm = -DBM; - cellinfo.signalStrengthEvdo.ecio = -ECIO; - cellinfo.signalStrengthEvdo.signalNoiseRatio = SIGNAL_NOISE_RATIO; - android.hardware.radio.V1_2.CellInfo record = new android.hardware.radio.V1_2.CellInfo(); - record.cellInfoType = TYPE_CDMA; - record.registered = false; - record.timeStampType = RIL_TIMESTAMP_TYPE_OEM_RIL; - record.timeStamp = TIMESTAMP; - record.cdma.add(cellinfo); - record.connectionStatus = 0; - ArrayList<Object> records = new ArrayList<>(); - records.add(record); - - return RILUtils.convertHalCellInfoList(records); - } - - @Test public void testSetupDataCall() throws Exception { ApnSetting apn = new ApnSetting.Builder() .setId(1234) @@ -2750,13 +2580,12 @@ public class RILTest extends TelephonyTest { .setPreferred(false) .build(); - mRILUnderTest.setupDataCall(AccessNetworkConstants.AccessNetworkType.EUTRAN, dp, false, - false, 0, null, DataCallResponse.PDU_SESSION_ID_NOT_SET, null, null, true, - obtainMessage()); + mRILUnderTest.setupDataCall(AccessNetworkConstants.AccessNetworkType.EUTRAN, dp, false, 0, + null, DataCallResponse.PDU_SESSION_ID_NOT_SET, null, null, true, obtainMessage()); ArgumentCaptor<DataProfile> dpiCaptor = ArgumentCaptor.forClass(DataProfile.class); verify(mDataProxy).setupDataCall(mSerialNumberCaptor.capture(), - anyInt(), eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), dpiCaptor.capture(), - eq(false), eq(false), anyInt(), any(), anyInt(), any(), any(), eq(true)); + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), dpiCaptor.capture(), + eq(false), anyInt(), any(), anyInt(), any(), any(), eq(true)); verifyRILResponse( mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_SETUP_DATA_CALL); DataProfile dpi = dpiCaptor.getValue(); @@ -2775,46 +2604,6 @@ public class RILTest extends TelephonyTest { } @Test - public void testFixupSignalStrength10() { - final int gsmWcdmaRssiDbm = -65; - - // Test the positive case where rat=UMTS and SignalStrength=GSM - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS) - .when(mServiceState).getRilVoiceRadioTechnology(); - - SignalStrength gsmSignalStrength = new SignalStrength( - new CellSignalStrengthCdma(), - new CellSignalStrengthGsm(gsmWcdmaRssiDbm, 1, CellInfo.UNAVAILABLE), - new CellSignalStrengthWcdma(), new CellSignalStrengthTdscdma(), - new CellSignalStrengthLte(), new CellSignalStrengthNr()); - SignalStrength result = mRILUnderTest.fixupSignalStrength10(gsmSignalStrength); - - assertTrue(result.getCellSignalStrengths(CellSignalStrengthGsm.class).isEmpty()); - assertFalse(result.getCellSignalStrengths(CellSignalStrengthWcdma.class).isEmpty()); - - // Even though the dBm values are equal, the above checks ensure that the value has - // been migrated to WCDMA (with no change in the top-level getDbm() result). - assertEquals(result.getDbm(), gsmSignalStrength.getDbm()); - - // Test the no-op case where rat=GSM and SignalStrength=GSM - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_GSM) - .when(mServiceState).getRilVoiceRadioTechnology(); - result = mRILUnderTest.fixupSignalStrength10(gsmSignalStrength); - assertEquals(result, gsmSignalStrength); - - // Check that non-GSM non-WCDMA signal strengths are also passed through. - SignalStrength lteSignalStrength = new SignalStrength( - new CellSignalStrengthCdma(), new CellSignalStrengthGsm(), - new CellSignalStrengthWcdma(), new CellSignalStrengthTdscdma(), - new CellSignalStrengthLte(CellInfo.UNAVAILABLE, - -120, -10, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, - CellInfo.UNAVAILABLE), new CellSignalStrengthNr()); - SignalStrength lteResult = mRILUnderTest.fixupSignalStrength10(lteSignalStrength); - - assertEquals(lteResult, lteSignalStrength); - } - - @Test public void testCreateCarrierRestrictionList() { ArrayList<CarrierIdentifier> carriers = new ArrayList<>(); carriers.add(new CarrierIdentifier("110", "120", null, null, null, null)); @@ -2857,7 +2646,7 @@ public class RILTest extends TelephonyTest { ArrayList<Carrier> result = RILUtils.convertToHalCarrierRestrictionList(carriers); - assertTrue(result.equals(expected)); + assertEquals(result, expected); } @Test @@ -2897,34 +2686,34 @@ public class RILTest extends TelephonyTest { @Test public void testAreUiccApplicationsEnabled_nullRadioProxy() throws Exception { // Not supported on Radio 1.0. - doReturn(null).when(mRILUnderTest).getRadioProxy(any()); + doReturn(null).when(mRILUnderTest).getRadioProxy(); Message message = obtainMessage(); mRILUnderTest.areUiccApplicationsEnabled(message); processAllMessages(); verify(mSimProxy, never()).areUiccApplicationsEnabled(mSerialNumberCaptor.capture()); // Sending message is handled by getRadioProxy when proxy is null. // areUiccApplicationsEnabled shouldn't explicitly send another callback. - assertEquals(null, message.obj); + assertNull(message.obj); } @Test - public void testSetGetCompatVersion() throws Exception { + public void testSetGetCompatVersion() { final int testRequest = RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT; // getCompactVersion should return null before first setting assertNull(mRILUnderTest.getCompatVersion(testRequest)); // first time setting any valid HalVersion will success - mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_4); - assertEquals(RIL.RADIO_HAL_VERSION_1_4, mRILUnderTest.getCompatVersion(testRequest)); + mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_5); + assertEquals(RIL.RADIO_HAL_VERSION_1_5, mRILUnderTest.getCompatVersion(testRequest)); // try to set a lower HalVersion will success - mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_3); - assertEquals(RIL.RADIO_HAL_VERSION_1_3, mRILUnderTest.getCompatVersion(testRequest)); + mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_4); + assertEquals(RIL.RADIO_HAL_VERSION_1_4, mRILUnderTest.getCompatVersion(testRequest)); // try to set a greater HalVersion will not success - mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_5); - assertEquals(RIL.RADIO_HAL_VERSION_1_3, mRILUnderTest.getCompatVersion(testRequest)); + mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_6); + assertEquals(RIL.RADIO_HAL_VERSION_1_4, mRILUnderTest.getCompatVersion(testRequest)); } @FlakyTest @@ -2963,8 +2752,61 @@ public class RILTest extends TelephonyTest { Message message = obtainMessage(); mRILUnderTest.getImei(message); AsyncResult ar = (AsyncResult) message.obj; - Assert.assertEquals(null, ar.result); + Assert.assertNull(ar.result); Assert.assertNotNull(ar.exception.getMessage()); Assert.assertEquals("REQUEST_NOT_SUPPORTED", ar.exception.getMessage()); } + + @Test + public void testRadioServiceInvokeHelper() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + HandlerThread handlerThread = new HandlerThread("testRilServiceInvokeHelper"); + handlerThread.start(); + Handler handler = new Handler(handlerThread.getLooper()) { + public void handleMessage(Message msg) { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar != null && ar.exception instanceof CommandException) { + CommandException.Error err = + ((CommandException) (ar.exception)).getCommandError(); + if (err == CommandException.Error.SYSTEM_ERR) { + latch.countDown(); + } + } + } + }; + + // RuntimeException + doThrow(new RuntimeException()).when(mDataProxy).getDataCallList(anyInt()); + mRILUnderTest.getDataCallList(handler.obtainMessage()); + assertTrue(latch.await(3, TimeUnit.SECONDS)); + + // RemoteException + doThrow(new RemoteException()).when(mDataProxy).getDataCallList(anyInt()); + mRILUnderTest.getDataCallList(handler.obtainMessage()); + assertEquals(mRILUnderTest.getRadioState(), TelephonyManager.RADIO_POWER_UNAVAILABLE); + } + + + @Test + public void testRadioServiceNotAvailable() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + HandlerThread handlerThread = new HandlerThread("testRadioServiceNotAvailable"); + handlerThread.start(); + Handler handler = new Handler(handlerThread.getLooper()) { + public void handleMessage(Message msg) { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar != null && ar.exception instanceof CommandException) { + CommandException.Error err = + ((CommandException) (ar.exception)).getCommandError(); + if (err == CommandException.Error.RADIO_NOT_AVAILABLE) { + latch.countDown(); + } + } + } + }; + + when(mDataProxy.isEmpty()).thenReturn(true); + mRILUnderTest.getDataCallList(handler.obtainMessage()); + assertTrue(latch.await(3, TimeUnit.SECONDS)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 5f592d19e0..c54285786d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -32,6 +32,7 @@ import static org.mockito.Matchers.nullable; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; @@ -98,6 +99,7 @@ import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.satellite.SatelliteController; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -144,6 +146,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { private ServiceStateTrackerTestHandler mSSTTestHandler; private PersistableBundle mBundle; private SatelliteController mSatelliteController; + private EmergencyStateTracker mEmergencyStateTracker; private static final int EVENT_REGISTERED_TO_NETWORK = 1; private static final int EVENT_SUBSCRIPTION_INFO_READY = 2; @@ -200,7 +203,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { listenerArgumentCaptor = ArgumentCaptor.forClass( CarrierConfigManager.CarrierConfigChangeListener.class); - sst = new ServiceStateTracker(mPhone, mSimulatedCommands); + sst = new ServiceStateTracker(mPhone, mSimulatedCommands, mFeatureFlags); verify(mCarrierConfigManager, atLeast(3)).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(2); @@ -257,7 +260,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSatelliteController = Mockito.mock(SatelliteController.class); replaceInstance(SatelliteController.class, "sInstance", null, mSatelliteController); - doReturn(new ArrayList<>()).when(mSatelliteController).getSatellitePlmnList(); + doReturn(new ArrayList<>()).when(mSatelliteController).getSatellitePlmnList(anyInt()); mContextFixture.putResource(R.string.kg_text_message_separator, " \u2014 "); @@ -268,6 +271,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { "com.android.phone"); mContextFixture.putResource(R.string.config_wlan_network_service_package, "com.xyz.iwlan.networkservice"); + doReturn(mIwlanNetworkServiceStub).when(mIwlanNetworkServiceStub).asBinder(); addNetworkService(); @@ -302,6 +306,10 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(true).when(mPackageManager) .hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA); + // Set cellular radio on after boot by default + mContextFixture.putBooleanResource( + R.bool.config_enable_cellular_on_boot_default, true); + mSSTTestHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); mSSTTestHandler.start(); waitUntilReady(); @@ -327,6 +335,10 @@ public class ServiceStateTrackerTest extends TelephonyTest { mContextFixture.putIntResource( com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 0); + // Set 1 as default behavior for enable_cellular_on_boot + mContextFixture.putBooleanResource( + com.android.internal.R.bool.config_enable_cellular_on_boot_default, true); + mBundle.putBoolean( CarrierConfigManager.KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL, true); mBundle.putInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT, 0); @@ -380,6 +392,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { sendCarrierConfigUpdate(PHONE_ID); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class); + replaceInstance(EmergencyStateTracker.class, "INSTANCE", null, mEmergencyStateTracker); + logd("ServiceStateTrackerTest -Setup!"); } @@ -470,6 +485,66 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); verify(mDataNetworkController, times(1)).unregisterDataNetworkControllerCallback(any()); assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + verify(mEmergencyStateTracker, never()).onCellularRadioPowerOffRequested(); + } + + @Test + public void testSetRadioPowerExitEmergencyMode() throws Exception { + doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported(); + + // Set up DSDS environment + GsmCdmaPhone phone2 = Mockito.mock(GsmCdmaPhone.class); + DataNetworkController dataNetworkController_phone2 = + Mockito.mock(DataNetworkController.class); + mPhones = new Phone[] {mPhone, phone2}; + replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); + doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController(); + doReturn(mSST).when(phone2).getServiceStateTracker(); + doReturn(false).when(mDataNetworkController).areAllDataDisconnected(); + doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected(); + doReturn(1).when(mPhone).getSubId(); + doReturn(2).when(phone2).getSubId(); + + // Start with radio on + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Turn on APM + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Verify checking emergency mode + verify(mEmergencyStateTracker).onCellularRadioPowerOffRequested(); + + // Verify that both subs are waiting for all data disconnected + verify(mDataNetworkController).tearDownAllDataNetworks( + eq(3 /* TEAR_DOWN_REASON_AIRPLANE_MODE_ON */)); + verify(dataNetworkController_phone2, never()).tearDownAllDataNetworks(anyInt()); + ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback1 = + ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); + ArgumentCaptor<DataNetworkController.DataNetworkControllerCallback> callback2 = + ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); + verify(mDataNetworkController, times(1)).registerDataNetworkControllerCallback( + callback1.capture()); + verify(dataNetworkController_phone2, times(1)).registerDataNetworkControllerCallback( + callback2.capture()); + + // Data disconnected on sub 2, still waiting for data disconnected on sub 1 + doReturn(true).when(dataNetworkController_phone2).areAllDataDisconnected(); + callback2.getValue().onAnyDataNetworkExistingChanged(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + verify(dataNetworkController_phone2, times(1)).unregisterDataNetworkControllerCallback( + any()); + + // Data disconnected on sub 1, radio should power off now + doReturn(true).when(mDataNetworkController).areAllDataDisconnected(); + callback1.getValue().onAnyDataNetworkExistingChanged(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + verify(mDataNetworkController, times(1)).unregisterDataNetworkControllerCallback(any()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test @@ -511,18 +586,22 @@ public class ServiceStateTrackerTest extends TelephonyTest { } private void testSetRadioPowerForReason(int reason) { + clearInvocations(mSatelliteController); // Radio does not turn on if off for other reason and not emergency call. assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); assertTrue(sst.getRadioPowerOffReasons().isEmpty()); sst.setRadioPowerForReason(false, false, false, false, reason); assertTrue(sst.getRadioPowerOffReasons().contains(reason)); assertTrue(sst.getRadioPowerOffReasons().size() == 1); + verify(mSatelliteController).onCellularRadioPowerOffRequested(); + clearInvocations(mSatelliteController); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); sst.setRadioPowerForReason(true, false, false, false, TelephonyManager.RADIO_POWER_REASON_USER); assertTrue(sst.getRadioPowerOffReasons().contains(reason)); assertTrue(sst.getRadioPowerOffReasons().size() == 1); + verify(mSatelliteController, never()).onCellularRadioPowerOffRequested(); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); @@ -530,6 +609,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { // had been turned off for. sst.setRadioPowerForReason(true, false, false, false, reason); assertTrue(sst.getRadioPowerOffReasons().isEmpty()); + verify(mSatelliteController, never()).onCellularRadioPowerOffRequested(); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); @@ -2050,6 +2130,79 @@ public class ServiceStateTrackerTest extends TelephonyTest { } @Test + public void testPollStateExceptionRadioPowerOn() { + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + assertEquals(ServiceState.STATE_IN_SERVICE, sst.getServiceState().getState()); + assertEquals(ServiceState.STATE_IN_SERVICE, + sst.getServiceState().getDataRegistrationState()); + + sst.mPollingContext[0] = 1; + sst.sendMessage(sst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_OPERATOR, + new AsyncResult(sst.mPollingContext, null, + new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE)))); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + assertEquals(ServiceState.STATE_IN_SERVICE, sst.getServiceState().getState()); + assertEquals(ServiceState.STATE_IN_SERVICE, + sst.getServiceState().getDataRegistrationState()); + assertEquals(0, sst.mPollingContext[0]); + } + + @Test + public void testPollStateExceptionRadioPowerOff() { + // Turn off radio first. + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getState()); + assertEquals(ServiceState.STATE_POWER_OFF, + sst.getServiceState().getDataRegistrationState()); + // Override service state + sst.getServiceState().setVoiceRegState(ServiceState.STATE_IN_SERVICE); + sst.getServiceState().setDataRegState(ServiceState.STATE_IN_SERVICE); + + sst.mPollingContext[0] = 1; + sst.sendMessage(sst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_OPERATOR, + new AsyncResult(sst.mPollingContext, null, + new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE)))); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getVoiceRegState()); + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getDataRegState()); + assertEquals(1, sst.mPollingContext[0]); + } + + @Test + public void testPollStateExceptionRadioPowerOffOnIwlan() { + // Turn off radio first. + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getState()); + assertEquals(ServiceState.STATE_POWER_OFF, + sst.getServiceState().getDataRegistrationState()); + // Override service state + sst.getServiceState().setVoiceRegState(ServiceState.STATE_IN_SERVICE); + sst.getServiceState().setDataRegState(ServiceState.STATE_IN_SERVICE); + // Override to IWLAN + sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN); + + sst.mPollingContext[0] = 1; + sst.sendMessage(sst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_OPERATOR, + new AsyncResult(sst.mPollingContext, null, + new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE)))); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + assertNull(null, sst.getServiceState().getOperatorAlpha()); + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getVoiceRegState()); + assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getDataRegState()); + assertEquals(1, sst.mPollingContext[0]); + } + + @Test public void testCSEmergencyRegistrationState() throws Exception { CellIdentityGsm cellIdentity = new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst", @@ -3233,7 +3386,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { CellIdentityGsm cellIdentity = new CellIdentityGsm(0, 1, 900, 5, "101", "23", "test", "tst", Collections.emptyList()); - doReturn(Arrays.asList("10123")).when(mSatelliteController).getSatellitePlmnList(); + doReturn(Arrays.asList("10123")).when(mSatelliteController).getSatellitePlmnList(anyInt()); doReturn(satelliteSupportedServiceList).when(mSatelliteController) .getSupportedSatelliteServices(sst.mSubId, "10123"); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java index e4617feaa8..fa890825f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java @@ -16,6 +16,9 @@ package com.android.internal.telephony; +import static android.telephony.ServiceState.STATE_IN_SERVICE; +import static android.telephony.ServiceState.STATE_OUT_OF_SERVICE; +import static android.telephony.ServiceState.STATE_POWER_OFF; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP; @@ -27,14 +30,19 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; @@ -1012,6 +1020,495 @@ public class SignalStrengthControllerTest extends TelephonyTest { assertThat(msgCaptor.getValue().what).isEqualTo(ssChangedEvent); } + @Test + public void testInvalidCarrierConfig_GERAN_RSSI_arrayIsTooLong() { + mBundle.putIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[]{ + -109, /* SIGNAL_STRENGTH_POOR */ + -103, /* SIGNAL_STRENGTH_MODERATE */ + -97, /* SIGNAL_STRENGTH_GOOD */ + -89, /* SIGNAL_STRENGTH_GREAT */ + -80, /* and extra value */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_GERAN_RSSI_arrayIsTooShort() { + mBundle.putIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[]{}); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_GERAN_RSSI_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-113, -51] + mBundle.putIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[]{ + -114, /* SIGNAL_STRENGTH_POOR */ + -103, /* SIGNAL_STRENGTH_MODERATE */ + -97, /* SIGNAL_STRENGTH_GOOD */ + -89, /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_GERAN_RSSI_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-113, -51] + mBundle.putIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[]{ + -109, /* SIGNAL_STRENGTH_POOR */ + -103, /* SIGNAL_STRENGTH_MODERATE */ + -97, /* SIGNAL_STRENGTH_GOOD */ + -89, /* SIGNAL_STRENGTH_GREAT */ + -50, /* and extra value */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_UTRAN_RSCP_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-120, -24] + mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY, + new int[]{ + -121, /* SIGNAL_STRENGTH_POOR */ + -104, /* SIGNAL_STRENGTH_MODERATE */ + -94, /* SIGNAL_STRENGTH_GOOD */ + -84 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_UTRAN_RSCP_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-120, -24] + mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY, + new int[]{ + -114, /* SIGNAL_STRENGTH_POOR */ + -104, /* SIGNAL_STRENGTH_MODERATE */ + -94, /* SIGNAL_STRENGTH_GOOD */ + -23 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSRP_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{ + -141, /* SIGNAL_STRENGTH_POOR */ + -118, /* SIGNAL_STRENGTH_MODERATE */ + -108, /* SIGNAL_STRENGTH_GOOD */ + -98, /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSRP_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{ + -128, /* SIGNAL_STRENGTH_POOR */ + -118, /* SIGNAL_STRENGTH_MODERATE */ + -108, /* SIGNAL_STRENGTH_GOOD */ + -43, /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSRQ_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-34, 3] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -35, /* SIGNAL_STRENGTH_POOR */ + -17, /* SIGNAL_STRENGTH_MODERATE */ + -14, /* SIGNAL_STRENGTH_GOOD */ + -11 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSRQ_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-34, 3] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -20, /* SIGNAL_STRENGTH_POOR */ + -17, /* SIGNAL_STRENGTH_MODERATE */ + -14, /* SIGNAL_STRENGTH_GOOD */ + 4 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSSNR_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-20, 30] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + new int[]{ + -21, /* SIGNAL_STRENGTH_POOR */ + 1, /* SIGNAL_STRENGTH_MODERATE */ + 5, /* SIGNAL_STRENGTH_GOOD */ + 13 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_EUTRAN_RSSNR_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-20, 30] + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + new int[]{ + -3, /* SIGNAL_STRENGTH_POOR */ + 1, /* SIGNAL_STRENGTH_MODERATE */ + 5, /* SIGNAL_STRENGTH_GOOD */ + 31 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSRSRP_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, + new int[]{ + -141, /* SIGNAL_STRENGTH_POOR */ + -107, /* SIGNAL_STRENGTH_MODERATE */ + -100, /* SIGNAL_STRENGTH_GOOD */ + -95, /* SIGNAL_STRENGTH_GREAT */ + -90, /* and extra value */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSRSRP_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, + new int[]{ + -113, /* SIGNAL_STRENGTH_POOR */ + -107, /* SIGNAL_STRENGTH_MODERATE */ + -100, /* SIGNAL_STRENGTH_GOOD */ + -95, /* SIGNAL_STRENGTH_GREAT */ + -45, /* and extra value */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSRSRQ_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-43, 20] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -44, /* SIGNAL_STRENGTH_POOR */ + -19, /* SIGNAL_STRENGTH_MODERATE */ + -7, /* SIGNAL_STRENGTH_GOOD */ + 6 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSRSRQ_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-43, 20] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -31, /* SIGNAL_STRENGTH_POOR */ + -19, /* SIGNAL_STRENGTH_MODERATE */ + -7, /* SIGNAL_STRENGTH_GOOD */ + 21 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSSINR_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-23, 40] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, + new int[]{ + -24, /* SIGNAL_STRENGTH_POOR */ + 5, /* SIGNAL_STRENGTH_MODERATE */ + 15, /* SIGNAL_STRENGTH_GOOD */ + 30 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NGRAN_SSSINR_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-24, 1] + mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY, + new int[]{ + -25, /* SIGNAL_STRENGTH_POOR */ + -14, /* SIGNAL_STRENGTH_MODERATE */ + -6, /* SIGNAL_STRENGTH_GOOD */ + 1 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_UTRAN_ECNO_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-24, 1] + mBundle.putIntArray(CarrierConfigManager.KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY, + new int[]{ + -24, /* SIGNAL_STRENGTH_POOR */ + -14, /* SIGNAL_STRENGTH_MODERATE */ + -6, /* SIGNAL_STRENGTH_GOOD */ + 2 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_UTRAN_ECNO_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-23, 40] + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY, + new int[]{ + -5, /* SIGNAL_STRENGTH_POOR */ + 5, /* SIGNAL_STRENGTH_MODERATE */ + 15, /* SIGNAL_STRENGTH_GOOD */ + 41 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSRP_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{ + -141, /* SIGNAL_STRENGTH_POOR */ + -118, /* SIGNAL_STRENGTH_MODERATE */ + -108, /* SIGNAL_STRENGTH_GOOD */ + -98 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSRP_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-140, -44] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -128, /* SIGNAL_STRENGTH_POOR */ + -118, /* SIGNAL_STRENGTH_MODERATE */ + -108, /* SIGNAL_STRENGTH_GOOD */ + -43, /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSRQ_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-34, 3] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -35, /* SIGNAL_STRENGTH_POOR */ + -17, /* SIGNAL_STRENGTH_MODERATE */ + -14, /* SIGNAL_STRENGTH_GOOD */ + -11 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSRQ_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-34, 3] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + new int[]{ + -20, /* SIGNAL_STRENGTH_POOR */ + -17, /* SIGNAL_STRENGTH_MODERATE */ + -14, /* SIGNAL_STRENGTH_GOOD */ + 4 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSSNR_thresholdIsTooSmall() { + // 4 threshold integers must be within the boundaries [-20, 30] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + new int[]{ + -21, /* SIGNAL_STRENGTH_POOR */ + 1, /* SIGNAL_STRENGTH_MODERATE */ + 5, /* SIGNAL_STRENGTH_GOOD */ + 13 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testInvalidCarrierConfig_NTN_LTE_RSSNR_thresholdIsTooLarge() { + // 4 threshold integers must be within the boundaries [-20, 30] + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + new int[]{ + -3, /* SIGNAL_STRENGTH_POOR */ + 1, /* SIGNAL_STRENGTH_MODERATE */ + 5, /* SIGNAL_STRENGTH_GOOD */ + 31 /* SIGNAL_STRENGTH_GREAT */ + }); + sendCarrierConfigUpdate(); + } + + @Test + public void testLteSignalStrengthReportingCriteriaWhenServiceStateChanged() { + SignalStrength ss = new SignalStrength( + new CellSignalStrengthCdma(), + new CellSignalStrengthGsm(), + new CellSignalStrengthWcdma(), + new CellSignalStrengthTdscdma(), + new CellSignalStrengthLte( + -110, /* rssi */ + -114, /* rsrp */ + -5, /* rsrq */ + 0, /* rssnr */ + SignalStrength.INVALID, /* cqi */ + SignalStrength.INVALID /* ta */), + new CellSignalStrengthNr()); + + // RSRP NTN_LTE threshold set to Good and LTE threshold set to poor. + mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT, + CellSignalStrengthLte.USE_RSRP); + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{-125 /* SIGNAL_STRENGTH_POOR */, -120 /* SIGNAL_STRENGTH_MODERATE */, + -115 /* SIGNAL_STRENGTH_GOOD */, -110/* SIGNAL_STRENGTH_GREAT */}); + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{-114, /* SIGNAL_STRENGTH_POOR */ -110, /* SIGNAL_STRENGTH_MODERATE */ + -105, /* SIGNAL_STRENGTH_GOOD */ -100, /* SIGNAL_STRENGTH_GREAT */}); + CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class); + when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) + .thenReturn(mockConfigManager); + when(mockConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); + + // When NTN is connected, check the signal strength is GOOD + AsyncResult asyncResult = mock(AsyncResult.class); + asyncResult.result = mServiceState; + doReturn(true).when(mServiceState).isUsingNonTerrestrialNetwork(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_GOOD, mSsc.getSignalStrength().getLevel()); + + // When TN connected, check the signal strength is POOR + doReturn(false).when(mServiceState).isUsingNonTerrestrialNetwork(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, mSsc.getSignalStrength().getLevel()); + + // RSRP NTN_LTE threshold set to Moderate and LTE threshold set to poor. + // When TN connected, check the signal strength is POOR. + mBundle.putIntArray(CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[]{-130 /* SIGNAL_STRENGTH_POOR */, -120 /* SIGNAL_STRENGTH_MODERATE */, + -110 /* SIGNAL_STRENGTH_GOOD */, -100/* SIGNAL_STRENGTH_GREAT */}); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, mSsc.getSignalStrength().getLevel()); + + // Service State Changed with OUT_OF_SERVICE, then no update + // SignalStrengthReportingCriteria. + reset(mSimulatedCommandsVerifier); + doReturn(STATE_OUT_OF_SERVICE).when(mServiceState).getState(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier, never()).setSignalStrengthReportingCriteria(anyList(), + isNull()); + + // Service State Changed with POWER_OFF, then no update SignalStrengthReportingCriteria. + reset(mSimulatedCommandsVerifier); + doReturn(STATE_POWER_OFF).when(mServiceState).getState(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier, never()).setSignalStrengthReportingCriteria(anyList(), + isNull()); + + // Service State Changed with IN_SERVICE, then update SignalStrengthReportingCriteria. + // When NTN is connected, check the signal strength is MODERATE + reset(mSimulatedCommandsVerifier); + doReturn(true).when(mServiceState).isUsingNonTerrestrialNetwork(); + doReturn(STATE_IN_SERVICE).when(mServiceState).getState(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_MODERATE, + mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier).setSignalStrengthReportingCriteria(anyList(), isNull()); + + // Service State Changed with IN_SERVICE and still NTN is connected, + // verify not update SignalStrengthReportingCriteria and the signal strength is MODERATE. + reset(mSimulatedCommandsVerifier); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_MODERATE, + mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier, never()).setSignalStrengthReportingCriteria(anyList(), + isNull()); + + // Service State Changed with IN_SERVICE, then update SignalStrengthReportingCriteria. + // When TN is connected, check the signal strength is POOR. + reset(mSimulatedCommandsVerifier); + doReturn(false).when(mServiceState).isUsingNonTerrestrialNetwork(); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, + mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier).setSignalStrengthReportingCriteria(anyList(), isNull()); + + // Service State Changed with IN_SERVICE and still TN is connected, + // verify not update SignalStrengthReportingCriteria and the signal strength is POOR. + reset(mSimulatedCommandsVerifier); + mSsc.handleMessage(mSsc.obtainMessage(10/*EVENT_SERVICE_STATE_CHANGED*/, asyncResult)); + processAllMessages(); + + mSimulatedCommands.setSignalStrength(ss); + mSimulatedCommands.notifySignalStrength(); + processAllMessages(); + assertEquals(CellSignalStrength.SIGNAL_STRENGTH_POOR, + mSsc.getSignalStrength().getLevel()); + verify(mSimulatedCommandsVerifier, never()).setSignalStrengthReportingCriteria(anyList(), + isNull()); + + reset(mSimulatedCommandsVerifier); + } + private void verifyAllEmptyThresholdAreDisabledWhenSetSignalStrengthReportingCriteria( int expectedNonEmptyThreshold) { ArgumentCaptor<List<SignalThresholdInfo>> signalThresholdInfoCaptor = diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java index 96184c5ec7..8df40527dc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue; import android.os.Parcel; import android.os.PersistableBundle; +import android.platform.test.flag.junit.SetFlagsRule; import android.telephony.CarrierConfigManager; import android.telephony.CellInfo; import android.telephony.CellSignalStrength; @@ -30,10 +31,16 @@ import android.telephony.CellSignalStrengthLte; import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; import android.telephony.SignalStrength; import androidx.test.filters.SmallTest; +import com.android.internal.telephony.flags.Flags; + +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -46,6 +53,7 @@ import java.util.List; @SmallTest @RunWith(JUnit4.class) public class SignalStrengthTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final int[] DEFAULT_LTE_RSRP_THRESHOLDS = { -128, // SIGNAL_STRENGTH_POOR -118, // SIGNAL_STRENGTH_MODERATE @@ -70,6 +78,42 @@ public class SignalStrengthTest { -105, // SIGNAL_STRENGTH_GOOD -95 }; // SIGNAL_STRENGTH_GREAT + private static final int[] DEFAULT_NTN_LTE_RSRP_THRESHOLDS = { + -118, // SIGNAL_STRENGTH_POOR + -108, // SIGNAL_STRENGTH_MODERATE + -98, // SIGNAL_STRENGTH_GOOD + -88 }; // SIGNAL_STRENGTH_GREAT + + private static final int[] DEFAULT_NTN_LTE_RSRQ_THRESHOLDS = { + -17, // SIGNAL_STRENGTH_POOR + -14, // SIGNAL_STRENGTH_MODERATE + -12, // SIGNAL_STRENGTH_GOOD + -10 }; // SIGNAL_STRENGTH_GREAT + + private static final int[] DEFAULT_NTN_LTE_RSSNR_THRESHOLDS = { + 1, // SIGNAL_STRENGTH_POOR + 5, // SIGNAL_STRENGTH_MODERATE + 13, // SIGNAL_STRENGTH_GOOD + 17 }; // SIGNAL_STRENGTH_GREAT + + // RSRP, RSSNR thresholds boundaries + private static final int MIN_RSRP = -140; + private static final int MIN_RSRQ = -34; + private static final int MAX_RSRQ = 3; + private static final int MIN_RSSNR = -20; + private static final int MAX_RSSNR = 30; + + // Default NTN & TN LTE thresholds's index + private static final int INDEX_SIGNAL_STRENGTH_POOR = 0; + private static final int INDEX_SIGNAL_STRENGTH_MODERATE = 1; + private static final int INDEX_SIGNAL_STRENGTH_GOOD = 2; + private static final int INDEX_SIGNAL_STRENGTH_GREAT = 3; + + @Before + public void setUp() { + mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG); + } + @Test public void testDefaults() throws Exception { SignalStrength s = new SignalStrength(); @@ -229,6 +273,58 @@ public class SignalStrengthTest { return signalStrength; } + private static SignalStrength createSignalStrengthLteReport(int lteRsrp, int lteRsrq, + int lteRssnr, boolean isNTN) { + CellSignalStrengthLte lte = new CellSignalStrengthLte( + -89, // rssi + lteRsrp, // rsrp + lteRsrq, // rsrq + lteRssnr, // rssnr + CellInfo.UNAVAILABLE, // cqiTableIndex + CellInfo.UNAVAILABLE, // cqi + CellInfo.UNAVAILABLE); // timingAdvance + + SignalStrength signalStrength = new SignalStrength( + new CellSignalStrengthCdma(), + new CellSignalStrengthGsm(), + new CellSignalStrengthWcdma(), + new CellSignalStrengthTdscdma(), + lte, + new CellSignalStrengthNr()); + + PersistableBundle bundle = new PersistableBundle(); + bundle.putInt( + CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, + CellSignalStrengthLte.USE_RSRP | CellSignalStrengthLte.USE_RSRQ + | CellSignalStrengthLte.USE_RSSNR); + bundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + DEFAULT_LTE_RSRP_THRESHOLDS); + bundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + DEFAULT_LTE_RSRQ_THRESHOLDS); + bundle.putIntArray(CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + DEFAULT_LTE_RSSNR_THRESHOLDS); + bundle.putInt( + CarrierConfigManager.KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT, + CellSignalStrengthLte.USE_RSRP | CellSignalStrengthLte.USE_RSRQ + | CellSignalStrengthLte.USE_RSSNR); + bundle.putIntArray( + CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY, + DEFAULT_NTN_LTE_RSRP_THRESHOLDS); + bundle.putIntArray( + CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY, + DEFAULT_NTN_LTE_RSRQ_THRESHOLDS); + bundle.putIntArray( + CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY, + DEFAULT_NTN_LTE_RSSNR_THRESHOLDS); + ServiceState serviceState = new ServiceState(); + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setIsNonTerrestrialNetwork(isNTN) + .build(); + serviceState.addNetworkRegistrationInfo(nri); + signalStrength.updateLevel(bundle, serviceState); + return signalStrength; + } + @Test public void testValidateInput() throws Exception { @@ -265,6 +361,44 @@ public class SignalStrengthTest { // Input value of RSSNR: -21[dB] ss = createSignalStrengthLteReportRssnr(60, -21); assertEquals(SignalStrength.INVALID, ss.getLteRssnr()); + + // Test for NTN LTE RSRQ Thresholds based on Boundaries [-34 dB, 3 dB] + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MAX_RSRQ + 1; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(SignalStrength.INVALID, ss.getLteRsrq()); + + rsrq = MAX_RSRQ; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(3, ss.getLteRsrq()); + + rsrq = MIN_RSRQ - 1; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(SignalStrength.INVALID, ss.getLteRsrq()); + + rsrq = MIN_RSRQ; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(-34, ss.getLteRsrq()); + + // Test for NTN LTE RSSNR Thresholds based on Boundaries [-20 dBm, 30 dBm] + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; // or 3 ? + rssnr = MAX_RSSNR + 1; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(SignalStrength.INVALID, ss.getLteRssnr()); + + rssnr = MAX_RSSNR; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(30, ss.getLteRssnr()); + + rssnr = MIN_RSSNR - 1; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(SignalStrength.INVALID, ss.getLteRssnr()); + + rssnr = MIN_RSSNR; + ss = createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN); + assertEquals(-20, ss.getLteRssnr()); } @Test @@ -279,6 +413,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRsrq(-98, -14).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, createSignalStrengthLteReportRsrq(-98, -12).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -293,6 +467,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRsrq(-108, -14).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, createSignalStrengthLteReportRsrq(-108, -12).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -307,6 +521,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRsrq(-118, -14).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, createSignalStrengthLteReportRsrq(-118, -12).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -321,6 +575,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRsrq(-128, -14).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, createSignalStrengthLteReportRsrq(-128, -12).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -335,6 +629,45 @@ public class SignalStrengthTest { createSignalStrengthLteReportRsrq(-138, -14).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, createSignalStrengthLteReportRsrq(-138, -12).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = MIN_RSRP; + int rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = MIN_RSRQ; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -349,6 +682,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRssnr(-98, 5).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, createSignalStrengthLteReportRssnr(-98, 13).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GREAT, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -363,6 +736,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRssnr(-108, 5).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, createSignalStrengthLteReportRssnr(-108, 13).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + int rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_GOOD, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -377,6 +790,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRssnr(-118, 5).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, createSignalStrengthLteReportRssnr(-118, 13).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + int rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_MODERATE, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -391,6 +844,46 @@ public class SignalStrengthTest { createSignalStrengthLteReportRssnr(-128, 5).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, createSignalStrengthLteReportRssnr(-128, 13).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = DEFAULT_NTN_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + int rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrp = DEFAULT_LTE_RSRP_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_POOR, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } @Test @@ -405,6 +898,45 @@ public class SignalStrengthTest { createSignalStrengthLteReportRssnr(-138, 5).getLteLevel()); assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, createSignalStrengthLteReportRssnr(-138, 13).getLteLevel()); + + // When NTN is connected, check the signal strength + boolean isNTN = true; + int rsrp = MIN_RSRP; + int rsrq = DEFAULT_NTN_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + int rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_NTN_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + + // When NTN is disconnected, check the signal strength + isNTN = false; + rsrq = DEFAULT_LTE_RSRQ_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + rssnr = MIN_RSSNR; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_POOR]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_MODERATE]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GOOD]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); + rssnr = DEFAULT_LTE_RSSNR_THRESHOLDS[INDEX_SIGNAL_STRENGTH_GREAT]; + assertEquals(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, + createSignalStrengthLteReport(rsrp, rsrq, rssnr, isNTN).getLteLevel()); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 1e4c9392ae..39c0cacf8a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -18,9 +18,10 @@ package com.android.internal.telephony.test; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.radio.RadioError; -import android.hardware.radio.V1_0.DataRegStateResult; -import android.hardware.radio.V1_0.SetupDataCallResult; -import android.hardware.radio.V1_0.VoiceRegStateResult; +import android.hardware.radio.V1_2.VoiceRegStateResult; +import android.hardware.radio.V1_4.DataRegStateResult; +import android.hardware.radio.V1_4.PdpProtocolType; +import android.hardware.radio.V1_4.SetupDataCallResult; import android.hardware.radio.modem.ImeiInfo; import android.net.KeepalivePacketData; import android.net.LinkProperties; @@ -76,7 +77,6 @@ import com.android.internal.telephony.uicc.AdnCapacity; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccIoResult; -import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.internal.telephony.uicc.ReceivedPhonebookRecords; import com.android.internal.telephony.uicc.SimPhonebookRecord; import com.android.telephony.Rlog; @@ -89,7 +89,6 @@ import java.util.concurrent.atomic.AtomicInteger; public class SimulatedCommands extends BaseCommands implements CommandsInterface, SimulatedRadioControl { private static final String LOG_TAG = "SimulatedCommands"; - private boolean mSupportsEid = true; private enum SimLockState { NONE, @@ -127,9 +126,6 @@ public class SimulatedCommands extends BaseCommands // arrive and returning null to the callers. public static final long ICC_SIM_CHALLENGE_TIMEOUT_MILLIS = 2500; - private String mImei; - private String mImeiSv; - //***** Instance Variables @UnsupportedAppUsage @@ -167,7 +163,6 @@ public class SimulatedCommands extends BaseCommands private boolean mShouldReturnCellInfo = true; private int[] mImsRegState; private IccCardStatus mIccCardStatus; - private IccSlotStatus mIccSlotStatus; private IccIoResult mIccIoResultForApduLogicalChannel; private int mChannelId = IccOpenLogicalChannelResponse.INVALID_CHANNEL; @@ -175,7 +170,7 @@ public class SimulatedCommands extends BaseCommands private Object mVoiceRegStateResult; int mPausedResponseCount; - ArrayList<Message> mPausedResponses = new ArrayList<Message>(); + ArrayList<Message> mPausedResponses = new ArrayList<>(); int mNextCallFailCause = CallFailCause.NORMAL_CLEARING; @@ -242,26 +237,6 @@ public class SimulatedCommands extends BaseCommands } } - public void setIccSlotStatus(IccSlotStatus iccSlotStatus) { - mIccSlotStatus = iccSlotStatus; - } - - @Override - public void getIccSlotsStatus(Message result) { - SimulatedCommandsVerifier.getInstance().getIccSlotsStatus(result); - if (mIccSlotStatus != null) { - resultSuccess(result, mIccSlotStatus); - } else { - resultFail(result, null, - new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED)); - } - } - - @Override - public void setLogicalToPhysicalSlotMapping(int[] physicalSlots, Message result) { - unimplemented(result); - } - @Override public void supplyIccPin(String pin, Message result) { if (mSimLockedState != SimLockState.REQUIRE_PIN) { @@ -575,15 +550,6 @@ public class SimulatedCommands extends BaseCommands } /** - * @deprecated - */ - @Deprecated - @Override - public void getPDPContextList(Message result) { - getDataCallList(result); - } - - /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -592,7 +558,7 @@ public class SimulatedCommands extends BaseCommands */ @Override public void getDataCallList(Message result) { - ArrayList<SetupDataCallResult> dcCallList = new ArrayList<SetupDataCallResult>(0); + ArrayList<SetupDataCallResult> dcCallList = new ArrayList<>(0); SimulatedCommandsVerifier.getInstance().getDataCallList(result); if (mSetupDataCallResult != null) { dcCallList.add(mSetupDataCallResult); @@ -659,40 +625,6 @@ public class SimulatedCommands extends BaseCommands resultSuccess(result, "012345678901234"); } - public void setIMEI(String imei) { - mImei = imei; - } - - /** - * returned message - * retMsg.obj = AsyncResult ar - * ar.exception carries exception on failure - * ar.userObject contains the original value of result.obj - * ar.result is String containing IMEI on success - */ - @Override - public void getIMEI(Message result) { - SimulatedCommandsVerifier.getInstance().getIMEI(result); - resultSuccess(result, mImei != null ? mImei : FAKE_IMEI); - } - - public void setIMEISV(String imeisv) { - mImeiSv = imeisv; - } - - /** - * returned message - * retMsg.obj = AsyncResult ar - * ar.exception carries exception on failure - * ar.userObject contains the original value of result.obj - * ar.result is String containing IMEISV on success - */ - @Override - public void getIMEISV(Message result) { - SimulatedCommandsVerifier.getInstance().getIMEISV(result); - resultSuccess(result, mImeiSv != null ? mImeiSv : FAKE_IMEISV); - } - /** * Hang up one individual connection. * returned message @@ -900,21 +832,6 @@ public class SimulatedCommands extends BaseCommands resultSuccess(result, mFailCause); } - /** - * @deprecated - */ - @Deprecated - @Override - public void getLastPdpFailCause (Message result) { - unimplemented(result); - } - - @Override - public void getLastDataCallFailCause(Message result) { - // - unimplemented(result); - } - @Override public void setMute (boolean enableMute, Message result) {unimplemented(result);} @@ -1059,10 +976,10 @@ public class SimulatedCommands extends BaseCommands Object ret = mDataRegStateResult; if (ret == null) { ret = new DataRegStateResult(); - ((DataRegStateResult) ret).regState = mDataRegState; - ((DataRegStateResult) ret).rat = mDataRadioTech; - ((DataRegStateResult) ret).maxDataCalls = mMaxDataCalls; - ((DataRegStateResult) ret).reasonDataDenied = mReasonForDenial; + ((DataRegStateResult) ret).base.regState = mDataRegState; + ((DataRegStateResult) ret).base.rat = mDataRadioTech; + ((DataRegStateResult) ret).base.maxDataCalls = mMaxDataCalls; + ((DataRegStateResult) ret).base.reasonDataDenied = mReasonForDenial; } resultSuccess(result, ret); @@ -1097,7 +1014,6 @@ public class SimulatedCommands extends BaseCommands @VisibleForTesting public int getGetOperatorCallCount() { - final int count = mGetOperatorCallCount.get(); return mGetOperatorCallCount.get(); } @@ -1212,32 +1128,31 @@ public class SimulatedCommands extends BaseCommands } @Override - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message result) { + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean allowRoaming, + int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, Message result) { SimulatedCommandsVerifier.getInstance().setupDataCall(accessNetworkType, dataProfile, - isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, - trafficDescriptor, matchAllRuleAllowed, result); + allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor, + matchAllRuleAllowed, result); if (mSetupDataCallResult == null) { try { mSetupDataCallResult = new SetupDataCallResult(); - mSetupDataCallResult.status = 0; + mSetupDataCallResult.cause = 0; mSetupDataCallResult.suggestedRetryTime = -1; mSetupDataCallResult.cid = 1; mSetupDataCallResult.active = 2; - mSetupDataCallResult.type = "IP"; + mSetupDataCallResult.type = PdpProtocolType.IP; mSetupDataCallResult.ifname = "rmnet_data7"; - mSetupDataCallResult.addresses = "12.34.56.78"; - mSetupDataCallResult.dnses = "98.76.54.32"; - mSetupDataCallResult.gateways = "11.22.33.44"; - mSetupDataCallResult.pcscf = - "fd00:976a:c305:1d::8 fd00:976a:c202:1d::7 fd00:976a:c305:1d::5"; + mSetupDataCallResult.addresses = new ArrayList<>(List.of("12.34.56.78")); + mSetupDataCallResult.dnses = new ArrayList<>(List.of("98.76.54.32")); + mSetupDataCallResult.gateways = new ArrayList<>(List.of("11.22.33.44")); + mSetupDataCallResult.pcscf = new ArrayList<>(List.of( + "fd00:976a:c305:1d::8 fd00:976a:c202:1d::7 fd00:976a:c305:1d::5")); mSetupDataCallResult.mtu = 1440; } catch (Exception e) { - + Rlog.e(LOG_TAG, "setupDataCall: e=" + e); } } @@ -1624,21 +1539,6 @@ public class SimulatedCommands extends BaseCommands resultSuccess(response, null); } - - @Override - public void resetRadio(Message result) { - unimplemented(result); - } - - @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - // Just echo back data - if (response != null) { - AsyncResult.forMessage(response).result = data; - response.sendToTarget(); - } - } - @Override public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo, Message response) { @@ -1649,15 +1549,6 @@ public class SimulatedCommands extends BaseCommands } } - @Override - public void invokeOemRilRequestStrings(String[] strings, Message response) { - // Just echo back data - if (response != null) { - AsyncResult.forMessage(response).result = strings; - response.sendToTarget(); - } - } - //***** SimulatedRadioControl @@ -2101,7 +1992,7 @@ public class SimulatedCommands extends BaseCommands if (!mShouldReturnCellInfo) return; if (mCellInfoList == null) { - ArrayList<CellInfo> mCellInfoList = new ArrayList(); + mCellInfoList = new ArrayList(); mCellInfoList.add(getCellInfoGsm()); } @@ -2119,14 +2010,14 @@ public class SimulatedCommands extends BaseCommands } @Override - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) { - SimulatedCommandsVerifier.getInstance().setInitialAttachApn(dataProfile, isRoaming, result); + public void setInitialAttachApn(DataProfile dataProfile, Message result) { + SimulatedCommandsVerifier.getInstance().setInitialAttachApn(dataProfile, result); resultSuccess(result, null); } @Override - public void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result) { - SimulatedCommandsVerifier.getInstance().setDataProfile(dps, isRoaming, result); + public void setDataProfile(DataProfile[] dps, Message result) { + SimulatedCommandsVerifier.getInstance().setDataProfile(dps, result); resultSuccess(result, null); } @@ -2231,22 +2122,6 @@ public class SimulatedCommands extends BaseCommands } @Override - public void startLceService(int report_interval_ms, boolean pullMode, Message result) { - SimulatedCommandsVerifier.getInstance().startLceService(report_interval_ms, pullMode, - result); - } - - @Override - public void stopLceService(Message result) { - unimplemented(result); - } - - @Override - public void pullLceData(Message result) { - unimplemented(result); - } - - @Override public void registerForLceInfo(Handler h, int what, Object obj) { SimulatedCommandsVerifier.getInstance().registerForLceInfo(h, what, obj); } @@ -2564,15 +2439,6 @@ public class SimulatedCommands extends BaseCommands new ReceivedPhonebookRecords(4, phonebookRecordInfoGroup), null)); } - public void setSupportsEid(boolean supportsEid) { - mSupportsEid = supportsEid; - } - - @Override - public boolean supportsEid() { - return mSupportsEid; - } - @Override public void getSimPhonebookCapacity(Message result) { resultSuccess(result, new AdnCapacity(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java index 4d1c104251..6fc56169f3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java @@ -688,11 +688,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void getPDPContextList(Message result) { - - } - - @Override public void getDataCallList(Message result) { } @@ -719,16 +714,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void getIMEI(Message result) { - - } - - @Override - public void getIMEISV(Message result) { - - } - - @Override public void hangupConnection(int gsmIndex, Message result) { } @@ -789,16 +774,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void getLastPdpFailCause(Message result) { - - } - - @Override - public void getLastDataCallFailCause(Message result) { - - } - - @Override public void setMute(boolean enableMute, Message response) { } @@ -1039,11 +1014,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void resetRadio(Message result) { - - } - - @Override public void setBandMode(int bandMode, Message response) { } @@ -1100,26 +1070,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - - } - - @Override - public void invokeOemRilRequestStrings(String[] strings, Message response) { - - } - - @Override - public void setOnUnsolOemHookRaw(Handler h, int what, Object obj) { - - } - - @Override - public void unSetOnUnsolOemHookRaw(Handler h) { - - } - - @Override public void sendTerminalResponse(String contents, Message response) { } @@ -1210,10 +1160,9 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message result) { + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean allowRoaming, + int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, Message result) { } @Override @@ -1247,14 +1196,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void getIccSlotsStatus(Message result) { - } - - @Override - public void setLogicalToPhysicalSlotMapping(int[] physicalSlots, Message result) { - } - - @Override public void requestIccSimAuthentication(int authContext, String data, String aid, Message response) { @@ -1284,12 +1225,12 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) { + public void setInitialAttachApn(DataProfile dataProfile, Message result) { } @Override - public void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result) { + public void setDataProfile(DataProfile[] dps, Message result) { } @@ -1378,21 +1319,6 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } @Override - public void startLceService(int reportIntervalMs, boolean pullMode, Message result) { - - } - - @Override - public void stopLceService(Message result) { - - } - - @Override - public void pullLceData(Message result) { - - } - - @Override public void registerForLceInfo(Handler h, int what, Object obj) { } @@ -1549,4 +1475,12 @@ public class SimulatedCommandsVerifier implements CommandsInterface { @Override public void cancelHandover(Message result, int callId) { } + + /** + * Register to listen for the changes in the primary IMEI with respect to the sim slot. + */ + @Override + public void registerForImeiMappingChanged(Handler h, int what, Object obj) { + + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index b073cd43c3..dc63932167 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -23,10 +23,12 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -59,6 +61,8 @@ import com.android.ims.ImsManager; import com.android.internal.telephony.domainselection.DomainSelectionConnection; import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; +import com.android.internal.telephony.emergency.EmergencyStateTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.uicc.IccUtils; import org.junit.After; @@ -80,8 +84,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { */ private static class TestSmsDispatchersController extends SmsDispatchersController { TestSmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, - SmsUsageMonitor usageMonitor, Looper looper) { - super(phone, storageMonitor, usageMonitor, looper); + SmsUsageMonitor usageMonitor, Looper looper, FeatureFlags featureFlags) { + super(phone, storageMonitor, usageMonitor, looper, featureFlags); } public DomainSelectionConnectionHolder testGetDomainSelectionConnectionHolder( @@ -104,6 +108,15 @@ public class SmsDispatchersControllerTest extends TelephonyTest { sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage, priority, expectMore, validityPeriod, messageId); } + + public void testNotifySmsSentToEmergencyStateTracker(String destAddr, long messageId) { + notifySmsSentToEmergencyStateTracker(destAddr, messageId); + } + + public void testNotifySmsSentFailedToEmergencyStateTracker(String destAddr, + long messageId) { + notifySmsSentFailedToEmergencyStateTracker(destAddr, messageId); + } } /** @@ -158,6 +171,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { private static final String ACTION_TEST_SMS_SENT = "TEST_SMS_SENT"; // Mocked classes + private FeatureFlags mFeatureFlags; private SMSDispatcher.SmsTracker mTracker; private PendingIntent mSentIntent; private TestImsSmsDispatcher mImsSmsDispatcher; @@ -165,6 +179,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { private TestSmsDispatcher mCdmaSmsDispatcher; private SmsDomainSelectionConnection mSmsDsc; private EmergencySmsDomainSelectionConnection mEmergencySmsDsc; + private EmergencyStateTracker mEmergencyStateTracker; + private CompletableFuture<Integer> mEmergencySmsFuture; private TestSmsDispatchersController mSmsDispatchersController; private boolean mInjectionCallbackTriggered = false; @@ -174,10 +190,10 @@ public class SmsDispatchersControllerTest extends TelephonyTest { public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mTracker = mock(SMSDispatcher.SmsTracker.class); + mFeatureFlags = mock(FeatureFlags.class); setupMockPackagePermissionChecks(); mSmsDispatchersController = new TestSmsDispatchersController(mPhone, mSmsStorageMonitor, - mSmsUsageMonitor, mTestableLooper.getLooper()); - setUpDomainSelectionConnectionAsNotSupported(); + mSmsUsageMonitor, mTestableLooper.getLooper(), mFeatureFlags); processAllMessages(); } @@ -191,6 +207,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mDscFuture = null; mSmsDispatchersController.dispose(); mSmsDispatchersController = null; + mFeatureFlags = null; super.tearDown(); } @@ -436,9 +453,11 @@ public class SmsDispatchersControllerTest extends TelephonyTest { public void testSendEmergencyTextWhenDomainPs() throws Exception { setUpDomainSelectionConnection(); setUpSmsDispatchers(); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null, "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true); @@ -463,12 +482,92 @@ public class SmsDispatchersControllerTest extends TelephonyTest { @Test @SmallTest - public void testNotifyDomainSelectionTerminated() throws Exception { + public void testSendEmergencyTextWhenEmergencyStateTrackerReturnsFailure() throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + setUpEmergencyStateTracker(DisconnectCause.OUT_OF_SERVICE); + + mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); + + // Verify the domain selection requested regardless of the result of EmergencyStateTracker. + verify(mEmergencySmsDsc).requestDomainSelection(any(), any()); + } + + @Test + @SmallTest + public void testNotifySmsSentToEmergencyStateTracker() throws Exception { + setUpDomainSelectionEnabled(true); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); + + mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L); + processAllMessages(); + + verify(mTelephonyManager).isEmergencyNumber(eq("911")); + verify(mEmergencyStateTracker).endSms(eq("1"), eq(true)); + } + + @Test + @SmallTest + public void testNotifySmsSentToEmergencyStateTrackerWithNonEmergencyNumber() throws Exception { + setUpDomainSelectionEnabled(true); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); + + mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("1234", 1L); + processAllMessages(); + + verify(mTelephonyManager).isEmergencyNumber(eq("1234")); + verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean()); + } + + @Test + @SmallTest + public void testNotifySmsSentToEmergencyStateTrackerWithoutEmergencyStateTracker() + throws Exception { + setUpDomainSelectionEnabled(true); + mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L); + + verify(mTelephonyManager, never()).isEmergencyNumber(anyString()); + } + + @Test + @SmallTest + public void testNotifySmsSentFailedToEmergencyStateTracker() throws Exception { + setUpDomainSelectionEnabled(true); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); + + mSmsDispatchersController.testNotifySmsSentFailedToEmergencyStateTracker("911", 1L); + processAllMessages(); + + verify(mTelephonyManager).isEmergencyNumber(eq("911")); + verify(mEmergencyStateTracker).endSms(eq("1"), eq(false)); + } + + @Test + @SmallTest + public void testNotifySmsSentFailedToEmergencyStateTrackerWithNonEmergencyNumber() + throws Exception { + setUpDomainSelectionEnabled(true); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); + + mSmsDispatchersController.testNotifySmsSentFailedToEmergencyStateTracker("1234", 1L); + processAllMessages(); + + verify(mTelephonyManager).isEmergencyNumber(eq("1234")); + verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean()); + } + + @Test + @SmallTest + public void testNotifyDomainSelectionTerminatedWhenImsAvailableAndNormalSms() throws Exception { setUpDomainSelectionConnection(); setUpSmsDispatchers(); + when(mImsSmsDispatcher.isAvailable()).thenReturn(true); mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -483,10 +582,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { DomainSelectionConnection.DomainSelectionConnectionCallback callback = captor.getValue(); assertNotNull(callback); - - mSmsDispatchersController.post(() -> { - callback.onSelectionTerminated(DisconnectCause.LOCAL); - }); + callback.onSelectionTerminated(DisconnectCause.LOCAL); processAllMessages(); verify(mSmsDsc, never()).finishSelection(); @@ -494,13 +590,49 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertFalse(holder.isDomainSelectionRequested()); assertEquals(0, holder.getPendingRequests().size()); - // We can use the IntentReceiver for receiving the sent result, but it can be reported as - // a flaky test since sometimes broadcasts can take a long time if the system is under load. - // At this point, we couldn't use the PendingIntent as a mock because it's a final class - // so this test checks the method in the IActivityManager when the PendingIntent#send(int) - // is called. - verify(mIActivityManager).sendIntentSender(any(), any(), any(), - eq(SmsManager.RESULT_ERROR_GENERIC_FAILURE), any(), any(), any(), any(), any()); + verify(mImsSmsDispatcher).sendText(eq("1111"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); + } + + @Test + @SmallTest + public void testNotifyDomainSelectionTerminatedWhenImsNotAvailableAndEmergencySms() + throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED); + when(mImsSmsDispatcher.isAvailable()).thenReturn(false); + when(mImsSmsDispatcher.isEmergencySmsSupport(anyString())).thenReturn(true); + + mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true); + ArgumentCaptor<DomainSelectionConnection.DomainSelectionConnectionCallback> captor = + ArgumentCaptor.forClass( + DomainSelectionConnection.DomainSelectionConnectionCallback.class); + verify(mEmergencySmsDsc).requestDomainSelection(any(), captor.capture()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + DomainSelectionConnection.DomainSelectionConnectionCallback callback = captor.getValue(); + assertNotNull(callback); + callback.onSelectionTerminated(DisconnectCause.LOCAL); + processAllMessages(); + + verify(mEmergencySmsDsc, never()).finishSelection(); + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + + verify(mImsSmsDispatcher).sendText(eq("911"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); } @Test @@ -511,6 +643,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -521,6 +654,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); verify(mSmsDsc).requestDomainSelection(any(), any()); assertNotNull(holder.getConnection()); @@ -539,6 +673,23 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertEquals(0, holder.getPendingRequests().size()); } + @Test + @SmallTest + public void testSendTextWhenFeatureFlagDisabledForSmsDomainSelection() throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(false); + + mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); + + // Expect that the domain selection logic will not be executed. + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + assertNull(holder); + } + private void switchImsSmsFormat(int phoneType) { mSimulatedCommands.setImsRegistrationState(new int[]{1, phoneType}); mSimulatedCommands.notifyImsNetworkStateChanged(); @@ -553,7 +704,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertTrue(mSmsDispatchersController.setImsManager(imsManager)); } - private void setUpDomainSelectionConnectionAsNotSupported() { + private void setUpDomainSelectionEnabled(boolean enabled) { mSmsDispatchersController.setDomainSelectionResolverProxy( new SmsDispatchersController.DomainSelectionResolverProxy() { @Override @@ -566,9 +717,10 @@ public class SmsDispatchersControllerTest extends TelephonyTest { @Override public boolean isDomainSelectionSupported() { - return false; + return true; } }); + when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(enabled); } private void setUpDomainSelectionConnection() { @@ -589,6 +741,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { return true; } }); + when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(true); mDscFuture = new CompletableFuture<>(); when(mSmsDsc.requestDomainSelection( @@ -620,6 +773,18 @@ public class SmsDispatchersControllerTest extends TelephonyTest { | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT); } + private void setUpEmergencyStateTracker(int result) throws Exception { + mEmergencySmsFuture = new CompletableFuture<Integer>(); + mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class); + replaceInstance(SmsDispatchersController.class, "mEmergencyStateTracker", + mSmsDispatchersController, mEmergencyStateTracker); + when(mEmergencyStateTracker.startEmergencySms(any(Phone.class), anyString(), anyBoolean())) + .thenReturn(mEmergencySmsFuture); + doNothing().when(mEmergencyStateTracker).endSms(anyString(), anyBoolean()); + mEmergencySmsFuture.complete(result); + when(mTelephonyManager.isEmergencyNumber(eq("911"))).thenReturn(true); + } + private void sendDataWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, boolean isCdmaMo) throws Exception { setUpDomainSelectionConnection(); @@ -628,6 +793,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { byte[] data = new byte[] { 0x01 }; mSmsDispatchersController.testSendData( "test-app", "1111", "2222", 8080, data, mSentIntent, null, false); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -663,6 +829,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, "test-app", false, 0, false, 10, false, 1L, false); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -704,6 +871,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { ArrayList<PendingIntent> deliveryIntents = new ArrayList<>(); mSmsDispatchersController.testSendMultipartText("1111", "2222", parts, sentIntents, deliveryIntents, null, "test-app", false, 0, false, 10, 1L); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -746,6 +914,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker, smsFormat); mSmsDispatchersController.sendRetrySms(mTracker); + processAllMessages(); SmsDispatchersController.DomainSelectionConnectionHolder holder = mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); @@ -782,6 +951,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mTracker.mUsesImsServiceForIms = true; mSmsDispatchersController.sendRetrySms(mTracker); + processAllMessages(); verify(mSmsDsc, never()).requestDomainSelection(any(), any()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java index 3bafe4d7e9..9fa88e26e0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java @@ -21,6 +21,8 @@ import android.os.Parcel; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import com.android.internal.telephony.flags.Flags; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -52,6 +54,7 @@ public class SubscriptionInfoTest { .setEhplmns(EHPLMNS) .setHplmns(HPLMNS) .setCountryIso("us") + .setOnlyNonTerrestrialNetwork(true) .build(); } @@ -71,6 +74,9 @@ public class SubscriptionInfoTest { assertThat(mSubscriptionInfoUT.getSubscriptionId()).isEqualTo(1); assertThat(mSubscriptionInfoUT.getSimSlotIndex()).isEqualTo(0); assertThat(mSubscriptionInfoUT.getIccId()).isEqualTo("890126042XXXXXXXXXXX"); + if (Flags.oemEnabledSatelliteFlag()) { + assertThat(mSubscriptionInfoUT.isOnlyNonTerrestrialNetwork()).isTrue(); + } } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java index a053c56131..ad66b550c4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java @@ -48,6 +48,7 @@ import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.util.test.FakeSettingsProvider; import com.android.server.pm.permission.LegacyPermissionManagerService; @@ -57,7 +58,6 @@ import org.junit.Test; import java.lang.reflect.Field; import java.util.Map; - @SmallTest public class TelephonyPermissionsTest { @@ -71,6 +71,7 @@ public class TelephonyPermissionsTest { // Mocked classes private Context mMockContext; + private FeatureFlags mMockFeatureFlag; private AppOpsManager mMockAppOps; private SubscriptionManager mMockSubscriptionManager; private ITelephony mMockTelephony; @@ -84,10 +85,12 @@ public class TelephonyPermissionsTest { private MockContentResolver mMockContentResolver; private FakeSettingsConfigProvider mFakeSettingsConfigProvider; + private FeatureFlags mRealFeatureFlagToBeRestored; @Before public void setUp() throws Exception { mMockContext = mock(Context.class); + mMockFeatureFlag = mock(FeatureFlags.class); mMockAppOps = mock(AppOpsManager.class); mMockSubscriptionManager = mock(SubscriptionManager.class); mMockTelephony = mock(ITelephony.class); @@ -129,13 +132,17 @@ public class TelephonyPermissionsTest { .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); when(mMockContext.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, PID, UID)).thenReturn(PackageManager.PERMISSION_DENIED); + + replaceFeatureFlag(mMockFeatureFlag); setTelephonyMockAsService(); } @After - public void tearDown() { + public void tearDown() throws Exception { + replaceFeatureFlag(mRealFeatureFlagToBeRestored); mMockContentResolver = null; mFakeSettingsConfigProvider = null; + mRealFeatureFlagToBeRestored = null; } @Test @@ -540,6 +547,30 @@ public class TelephonyPermissionsTest { UserHandle.SYSTEM, "911")); } + @Test + public void testCheckSubscriptionAssociatedWithUser_badSub_flag_enabled() { + doReturn(true).when(mMockFeatureFlag).rejectBadSubIdInteraction(); + + doThrow(new IllegalArgumentException("has no records on device")) + .when(mMockSubscriptionManager).isSubscriptionAssociatedWithUser(SUB_ID, + UserHandle.SYSTEM); + assertFalse(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext, SUB_ID, + UserHandle.SYSTEM)); + } + + @Test + public void testCheckSubscriptionAssociatedWithUser_badSub_flag_disabled() { + doReturn(false).when(mMockFeatureFlag).rejectBadSubIdInteraction(); + + doThrow(new IllegalArgumentException("No records found for sub")) + .when(mMockSubscriptionManager).isSubscriptionAssociatedWithUser(SUB_ID, + UserHandle.SYSTEM); + assertTrue(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext, SUB_ID, + UserHandle.SYSTEM)); + assertTrue(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, UserHandle.SYSTEM)); + } + // Put mMockTelephony into service cache so that TELEPHONY_SUPPLIER will get it. private void setTelephonyMockAsService() throws Exception { when(mMockTelephonyBinder.queryLocalInterface(anyString())).thenReturn(mMockTelephony); @@ -630,4 +661,12 @@ public class TelephonyPermissionsTest { field.set(providerHolder, iContentProvider); } + private synchronized void replaceFeatureFlag(final FeatureFlags newValue) + throws Exception { + Field field = TelephonyPermissions.class.getDeclaredField("sFeatureFlag"); + field.setAccessible(true); + + mRealFeatureFlagToBeRestored = (FeatureFlags) field.get(null); + field.set(null, newValue); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 35a3186046..5a5e11f62f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -108,6 +108,7 @@ public class TelephonyRegistryTest extends TelephonyTest { private int mRadioPowerState = RADIO_POWER_UNAVAILABLE; private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN; private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; private List<PhysicalChannelConfig> mPhysicalChannelConfigs; private CellLocation mCellLocation; private List<CellInfo> mCellInfo; @@ -185,7 +186,8 @@ public class TelephonyRegistryTest extends TelephonyTest { TelephonyCallback.ServiceStateListener, TelephonyCallback.CellInfoListener, TelephonyCallback.BarringInfoListener, - TelephonyCallback.RegistrationFailedListener { + TelephonyCallback.RegistrationFailedListener, + TelephonyCallback.DataActivityListener { // This class isn't mockable to get invocation counts because the IBinder is null and // crashes the TelephonyRegistry. Make a cheesy verify(times()) alternative. public AtomicInteger invocationCount = new AtomicInteger(0); @@ -268,6 +270,11 @@ public class TelephonyRegistryTest extends TelephonyTest { mCellIdentityForRegiFail = cellIdentity; mRegistrationFailReason = causeCode; } + + public void onDataActivity(@Annotation.DataActivityType int direction) { + invocationCount.incrementAndGet(); + mDataActivity = direction; + } } private void addTelephonyRegistryService() { @@ -1490,4 +1497,38 @@ public class TelephonyRegistryTest extends TelephonyTest { assertEquals(2, mTelephonyCallback.invocationCount.get()); assertEquals(mCellInfo, dummyCellInfo); } + + @Test + public void testNotifyDataActivityForSubscriberWithSlot() { + final int subId = 1; + int[] events = {TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED}; + doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); + doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex(); + + assertEquals(TelephonyManager.DATA_ACTIVITY_NONE, mDataActivity); + mTelephonyRegistry.listenWithEventList(false, false, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); + + mTelephonyRegistry.notifyDataActivityForSubscriberWithSlot(0/*phoneId*/, subId, + TelephonyManager.DATA_ACTIVITY_INOUT); + processAllMessages(); + assertEquals(TelephonyManager.DATA_ACTIVITY_INOUT, mDataActivity); + } + + @Test + public void testNotifyDataActivityForSubscriberWithSlotForInvalidSubId() { + final int subId = INVALID_SUBSCRIPTION_ID; + int[] events = {TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED}; + doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); + doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex(); + + assertEquals(TelephonyManager.DATA_ACTIVITY_NONE, mDataActivity); + mTelephonyRegistry.listenWithEventList(false, false, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); + + mTelephonyRegistry.notifyDataActivityForSubscriberWithSlot(0/*phoneId*/, subId, + TelephonyManager.DATA_ACTIVITY_OUT); + processAllMessages(); + assertEquals(TelephonyManager.DATA_ACTIVITY_OUT, mDataActivity); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 705bafdf75..921256714c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -64,6 +64,7 @@ import android.os.MessageQueue; import android.os.RegistrantList; import android.os.ServiceManager; import android.os.StrictMode; +import android.os.SystemClock; import android.os.UserManager; import android.permission.LegacyPermissionManager; import android.provider.BlockedNumberContract; @@ -94,6 +95,7 @@ import android.util.Singleton; import com.android.ims.ImsCall; import com.android.ims.ImsEcbm; import com.android.ims.ImsManager; +import com.android.internal.telephony.analytics.TelephonyAnalytics; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.data.AccessNetworksManager; @@ -106,7 +108,9 @@ import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; @@ -119,6 +123,7 @@ import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; import com.android.internal.telephony.satellite.SatelliteController; +import com.android.internal.telephony.security.CellularIdentifierDisclosureNotifier; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; @@ -146,12 +151,12 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; public abstract class TelephonyTest { protected static String TAG; @@ -182,6 +187,7 @@ public abstract class TelephonyTest { } // Mocked classes + protected FeatureFlags mFeatureFlags; protected GsmCdmaPhone mPhone; protected GsmCdmaPhone mPhone2; protected ImsPhone mImsPhone; @@ -260,6 +266,7 @@ public abstract class TelephonyTest { protected PersistAtomsStorage mPersistAtomsStorage; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; + protected TelephonyAnalytics mTelephonyAnalytics; protected SignalStrength mSignalStrength; protected WifiManager mWifiManager; protected WifiInfo mWifiInfo; @@ -274,6 +281,8 @@ public abstract class TelephonyTest { protected ServiceStateStats mServiceStateStats; protected SatelliteController mSatelliteController; protected DeviceStateHelper mDeviceStateHelper; + protected CellularIdentifierDisclosureNotifier mIdentifierDisclosureNotifier; + protected DomainSelectionResolver mDomainSelectionResolver; // Initialized classes protected ActivityManager mActivityManager; @@ -296,7 +305,7 @@ public abstract class TelephonyTest { protected Context mContext; protected FakeBlockedNumberContentProvider mFakeBlockedNumberContentProvider; private final ContentProvider mContentProvider = spy(new ContextFixture.FakeContentProvider()); - private Object mLock = new Object(); + private final Object mLock = new Object(); private boolean mReady; protected HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>(); protected Phone[] mPhones; @@ -310,7 +319,37 @@ public abstract class TelephonyTest { private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>(); - private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>(); + private final List<InstanceKey> mInstanceKeys = new ArrayList<>(); + + protected int mIntegerConsumerResult; + protected Semaphore mIntegerConsumerSemaphore = new Semaphore(0); + protected Consumer<Integer> mIntegerConsumer = new Consumer<Integer>() { + @Override + public void accept(Integer integer) { + logd("mIIntegerConsumer: result=" + integer); + mIntegerConsumerResult = integer; + try { + mIntegerConsumerSemaphore.release(); + } catch (Exception ex) { + logd("mIIntegerConsumer: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + protected boolean waitForIntegerConsumerResponse(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIntegerConsumerSemaphore.tryAcquire(500 /*Timeout*/, TimeUnit.MILLISECONDS)) { + logd("Timeout to receive IIntegerConsumer() callback"); + return false; + } + } catch (Exception ex) { + logd("waitForIIntegerConsumerResult: Got exception=" + ex); + return false; + } + } + return true; + } private class InstanceKey { public final Class mClass; @@ -329,7 +368,7 @@ public abstract class TelephonyTest { @Override public boolean equals(Object obj) { - if (obj == null || obj.getClass() != getClass()) { + if (obj == null || !(obj instanceof InstanceKey)) { return false; } @@ -341,15 +380,18 @@ public abstract class TelephonyTest { protected void waitUntilReady() { synchronized (mLock) { - if (!mReady) { + long now = SystemClock.elapsedRealtime(); + long deadline = now + MAX_INIT_WAIT_MS; + while (!mReady && now < deadline) { try { mLock.wait(MAX_INIT_WAIT_MS); - } catch (InterruptedException ie) { - } - - if (!mReady) { - fail("Telephony tests failed to initialize"); + } catch (Exception e) { + fail("Telephony tests failed to initialize: e=" + e); } + now = SystemClock.elapsedRealtime(); + } + if (!mReady) { + fail("Telephony tests failed to initialize"); } } } @@ -388,10 +430,8 @@ public abstract class TelephonyTest { } protected synchronized void restoreInstances() throws Exception { - Iterator<InstanceKey> it = mInstanceKeys.descendingIterator(); - - while (it.hasNext()) { - InstanceKey key = it.next(); + for (int i = mInstanceKeys.size() - 1; i >= 0; i--) { + InstanceKey key = mInstanceKeys.get(i); Field field = key.mClass.getDeclaredField(key.mInstName); field.setAccessible(true); field.set(key.mObj, mOldInstances.get(key)); @@ -419,6 +459,7 @@ public abstract class TelephonyTest { protected void setUp(String tag) throws Exception { TAG = tag; enableStrictMode(); + mFeatureFlags = Mockito.mock(FeatureFlags.class); mPhone = Mockito.mock(GsmCdmaPhone.class); mPhone2 = Mockito.mock(GsmCdmaPhone.class); mImsPhone = Mockito.mock(ImsPhone.class); @@ -497,6 +538,7 @@ public abstract class TelephonyTest { mPersistAtomsStorage = Mockito.mock(PersistAtomsStorage.class); mMetricsCollector = Mockito.mock(MetricsCollector.class); mSmsStats = Mockito.mock(SmsStats.class); + mTelephonyAnalytics = Mockito.mock(TelephonyAnalytics.class); mSignalStrength = Mockito.mock(SignalStrength.class); mWifiManager = Mockito.mock(WifiManager.class); mWifiInfo = Mockito.mock(WifiInfo.class); @@ -511,6 +553,8 @@ public abstract class TelephonyTest { mServiceStateStats = Mockito.mock(ServiceStateStats.class); mSatelliteController = Mockito.mock(SatelliteController.class); mDeviceStateHelper = Mockito.mock(DeviceStateHelper.class); + mIdentifierDisclosureNotifier = Mockito.mock(CellularIdentifierDisclosureNotifier.class); + mDomainSelectionResolver = Mockito.mock(DomainSelectionResolver.class); TelephonyManager.disableServiceHandleCaching(); PropertyInvalidatedCache.disableForTestMode(); @@ -572,7 +616,7 @@ public abstract class TelephonyTest { doReturn(mTelephonyComponentFactory).when(mTelephonyComponentFactory).inject(anyString()); doReturn(mSST).when(mTelephonyComponentFactory) .makeServiceStateTracker(nullable(GsmCdmaPhone.class), - nullable(CommandsInterface.class)); + nullable(CommandsInterface.class), nullable(FeatureFlags.class)); doReturn(mEmergencyNumberTracker).when(mTelephonyComponentFactory) .makeEmergencyNumberTracker(nullable(Phone.class), nullable(CommandsInterface.class)); @@ -587,11 +631,11 @@ public abstract class TelephonyTest { doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory) .makeIccPhoneBookInterfaceManager(nullable(Phone.class)); doReturn(mDisplayInfoController).when(mTelephonyComponentFactory) - .makeDisplayInfoController(nullable(Phone.class)); + .makeDisplayInfoController(nullable(Phone.class), any(FeatureFlags.class)); doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory) .makeWspTypeDecoder(nullable(byte[].class)); doReturn(mImsCT).when(mTelephonyComponentFactory) - .makeImsPhoneCallTracker(nullable(ImsPhone.class)); + .makeImsPhoneCallTracker(nullable(ImsPhone.class), any(FeatureFlags.class)); doReturn(mCdmaSSM).when(mTelephonyComponentFactory) .getCdmaSubscriptionSourceManagerInstance(nullable(Context.class), nullable(CommandsInterface.class), nullable(Handler.class), @@ -607,7 +651,7 @@ public abstract class TelephonyTest { doReturn(mCarrierActionAgent).when(mTelephonyComponentFactory) .makeCarrierActionAgent(nullable(Phone.class)); doReturn(mDeviceStateMonitor).when(mTelephonyComponentFactory) - .makeDeviceStateMonitor(nullable(Phone.class)); + .makeDeviceStateMonitor(nullable(Phone.class), any(FeatureFlags.class)); doReturn(mAccessNetworksManager).when(mTelephonyComponentFactory) .makeAccessNetworksManager(nullable(Phone.class), any(Looper.class)); doReturn(mNitzStateMachine).when(mTelephonyComponentFactory) @@ -622,7 +666,11 @@ public abstract class TelephonyTest { doReturn(mDataProfileManager).when(mTelephonyComponentFactory) .makeDataProfileManager(any(Phone.class), any(DataNetworkController.class), any(DataServiceManager.class), any(Looper.class), + any(FeatureFlags.class), any(DataProfileManager.DataProfileManagerCallback.class)); + doReturn(mIdentifierDisclosureNotifier) + .when(mTelephonyComponentFactory) + .makeIdentifierDisclosureNotifier(); //mPhone doReturn(mContext).when(mPhone).getContext(); @@ -653,6 +701,7 @@ public abstract class TelephonyTest { doReturn(mVoiceCallSessionStats).when(mPhone).getVoiceCallSessionStats(); doReturn(mVoiceCallSessionStats).when(mImsPhone).getVoiceCallSessionStats(); doReturn(mSmsStats).when(mPhone).getSmsStats(); + doReturn(mTelephonyAnalytics).when(mPhone).getTelephonyAnalytics(); doReturn(mImsStats).when(mImsPhone).getImsStats(); mIccSmsInterfaceManager.mDispatchersController = mSmsDispatchersController; doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator(); @@ -702,7 +751,7 @@ public abstract class TelephonyTest { doReturn(mSimRecords).when(mUiccProfile).getIccRecords(); doAnswer(new Answer<IccRecords>() { public IccRecords answer(InvocationOnMock invocation) { - return (mPhone.isPhoneTypeGsm()) ? mSimRecords : mRuimRecords; + return mSimRecords; } }).when(mUiccProfile).getIccRecords(); @@ -842,6 +891,9 @@ public abstract class TelephonyTest { .getFoldState(); doReturn(null).when(mContext).getSystemService(eq(Context.DEVICE_STATE_SERVICE)); + doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); + //Use reflection to mock singletons replaceInstance(CallManager.class, "INSTANCE", null, mCallManager); replaceInstance(TelephonyComponentFactory.class, "sInstance", null, @@ -912,7 +964,9 @@ public abstract class TelephonyTest { } if (mContext != null) { SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0); - sharedPreferences.edit().clear().commit(); + if (sharedPreferences != null) { + sharedPreferences.edit().clear().commit(); + } } restoreInstances(); TelephonyManager.enableServiceHandleCaching(); @@ -936,13 +990,13 @@ public abstract class TelephonyTest { mContextFixture = null; mContext = null; mFakeBlockedNumberContentProvider = null; - mLock = null; mServiceManagerMockedServices.clear(); mServiceManagerMockedServices = null; mPhone = null; mTestableLoopers.clear(); mTestableLoopers = null; mTestableLooper = null; + DomainSelectionResolver.setDomainSelectionResolver(null); } protected static void logd(String s) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/analytics/CallAnalyticsProviderTest.java b/tests/telephonytests/src/com/android/internal/telephony/analytics/CallAnalyticsProviderTest.java new file mode 100644 index 0000000000..076ee0639c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/analytics/CallAnalyticsProviderTest.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.CallAnalyticsTable; +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.ContentValues; +import android.database.Cursor; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Calendar; + +public class CallAnalyticsProviderTest { + + @Mock TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + @Mock Cursor mCursor; + private CallAnalyticsProvider mCallAnalyticsProvider; + private ContentValues mContentValues; + + enum CallStatus { + SUCCESS("Success"), + FAILURE("Failure"); + public String value; + + CallStatus(String value) { + this.value = value; + } + } + + enum CallType { + NORMAL("Normal Call"), + SOS("SOS Call"); + public String value; + + CallType(String value) { + this.value = value; + } + } + + final String[] mCallInsertionProjection = { + TelephonyAnalyticsDatabase.CallAnalyticsTable._ID, + TelephonyAnalyticsDatabase.CallAnalyticsTable.COUNT + }; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + final String createCallAnalyticsTable = + "CREATE TABLE IF NOT EXISTS " + + TelephonyAnalyticsDatabase.CallAnalyticsTable.TABLE_NAME + + "(" + + TelephonyAnalyticsDatabase.CallAnalyticsTable._ID + + " INTEGER PRIMARY KEY," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.LOG_DATE + + " DATE ," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.CALL_STATUS + + " TEXT DEFAULT ''," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.CALL_TYPE + + " TEXT DEFAULT ''," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.RAT + + " TEXT DEFAULT ''," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.SLOT_ID + + " INTEGER ," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.FAILURE_REASON + + " TEXT DEFAULT ''," + + TelephonyAnalyticsDatabase.CallAnalyticsTable.RELEASE_VERSION + + " TEXT DEFAULT '' , " + + TelephonyAnalyticsDatabase.CallAnalyticsTable.COUNT + + " INTEGER DEFAULT 1 " + + ");"; + mCallAnalyticsProvider = new CallAnalyticsProvider(mTelephonyAnalyticsUtil, 0); + verify(mTelephonyAnalyticsUtil).createTable(createCallAnalyticsTable); + } + + @Test + public void testAggregate() { + String[] columns = {"sum(" + CallAnalyticsTable.COUNT + ")"}; + + when(mTelephonyAnalyticsUtil.getCursor( + eq(CallAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + when(mTelephonyAnalyticsUtil.getCursor( + anyString(), + any(String[].class), + anyString(), + any(String[].class), + anyString(), + isNull(), + anyString(), + anyString())) + .thenReturn(mCursor); + + when(mTelephonyAnalyticsUtil.getCountFromCursor(eq(mCursor))) + .thenReturn( + 100L /*totalCalls*/, + 50L /*totalFailedCalls*/, + 40L /*normalCalls*/, + 10L /*failedNormalCall*/, + 60L /*sosCalls*/, + 40L /*failedSosCall*/); + ArrayList<String> actual = mCallAnalyticsProvider.aggregate(); + verify(mTelephonyAnalyticsUtil, times(6)) + .getCursor( + eq(CallAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull()); + assertEquals("\tTotal Normal Calls = " + 40 /*normalCalls*/, actual.get(1)); + assertEquals("\tPercentage Failure of Normal Calls = 25.00%", actual.get(2)); + } + + @Test + public void testGetMaxFailureVersion() { + String[] columns = {CallAnalyticsTable.RELEASE_VERSION}; + String selection = + CallAnalyticsTable.CALL_STATUS + " = ? AND " + CallAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {"Failure", Integer.toString(0 /* slotIndex */)}; + String groupBy = CallAnalyticsTable.RELEASE_VERSION; + String orderBy = "SUM(" + CallAnalyticsTable.COUNT + ") DESC "; + String limit = "1"; + when(mTelephonyAnalyticsUtil.getCursor( + anyString(), + any(String[].class), + anyString(), + any(String[].class), + anyString(), + isNull(), + anyString(), + anyString())) + .thenReturn(mCursor); + when(mTelephonyAnalyticsUtil.getCountFromCursor(any(Cursor.class))) + .thenReturn(10L /* count */); + when(mTelephonyAnalyticsUtil.getCountFromCursor(isNull())).thenReturn(10L /* count */); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(CallAnalyticsTable.RELEASE_VERSION)) + .thenReturn(0 /* releaseVersionColumnIndex */); + when(mCursor.getString(0)).thenReturn("1.1.1.1" /* version */); + ArrayList<String> actual = mCallAnalyticsProvider.aggregate(); + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(CallAnalyticsTable.TABLE_NAME), + eq(columns), + eq(selection), + eq(selectionArgs), + eq(groupBy), + isNull(), + eq(orderBy), + eq(limit)); + assertEquals( + actual.get(actual.size() - 2 /* array index for max failure at version info */), + "\tMax Call(Normal+SOS) Failures at Version : 1.1.1.1"); + } + + private ContentValues getContentValues( + String callType, String callStatus, int slotId, String rat, String failureReason) { + ContentValues values = new ContentValues(); + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(CallAnalyticsTable.LOG_DATE, dateToday); + values.put(CallAnalyticsTable.CALL_TYPE, callType); + values.put(CallAnalyticsTable.CALL_STATUS, callStatus); + values.put(CallAnalyticsTable.SLOT_ID, slotId); + values.put(CallAnalyticsTable.RAT, rat); + values.put(CallAnalyticsTable.FAILURE_REASON, failureReason); + values.put(CallAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + return values; + } + + private void whenConditionForGetCursor() { + when(mTelephonyAnalyticsUtil.getCursor( + anyString(), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + } + + private void verifyForGetCursor( + String[] callInsertionProjection, + String callSuccessInsertionSelection, + String[] selectionArgs) { + + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(TelephonyAnalyticsDatabase.CallAnalyticsTable.TABLE_NAME), + eq(callInsertionProjection), + eq(callSuccessInsertionSelection), + eq(selectionArgs), + isNull(), + isNull(), + isNull(), + isNull()); + } + + @Test + public void testSuccessCall() { + int slotId = 0; + String callType = "Normal Call"; + String callStatus = "Success"; + String rat = "LTE"; + String failureReason = "User Disconnects"; + int count = 5; + + final String callSuccessInsertionSelection = + TelephonyAnalyticsDatabase.CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + TelephonyAnalyticsDatabase.CallAnalyticsTable.LOG_DATE + + " = ? AND " + + TelephonyAnalyticsDatabase.CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + TelephonyAnalyticsDatabase.CallAnalyticsTable.SLOT_ID + + " = ? "; + ContentValues values = getContentValues(callType, callStatus, slotId, rat, failureReason); + + String[] selectionArgs = + new String[] { + values.getAsString(TelephonyAnalyticsDatabase.CallAnalyticsTable.CALL_TYPE), + values.getAsString(TelephonyAnalyticsDatabase.CallAnalyticsTable.LOG_DATE), + callStatus, + values.getAsString(TelephonyAnalyticsDatabase.CallAnalyticsTable.SLOT_ID) + }; + whenConditionForGetCursor(); + mCallAnalyticsProvider.insertDataToDb(callType, callStatus, slotId, rat, failureReason); + verifyForGetCursor(mCallInsertionProjection, callSuccessInsertionSelection, selectionArgs); + } + + @Test + public void testFailureCall() { + int slotId = 0; + String callType = "Normal Call"; + String callStatus = "Failure"; + String rat = "LTE"; + String failureReason = "Network Detach"; + int count = 5; + final String callFailedInsertionSelection = + CallAnalyticsTable.LOG_DATE + + " = ? AND " + + CallAnalyticsTable.CALL_STATUS + + " = ? AND " + + CallAnalyticsTable.CALL_TYPE + + " = ? AND " + + CallAnalyticsTable.SLOT_ID + + " = ? AND " + + CallAnalyticsTable.RAT + + " = ? AND " + + CallAnalyticsTable.FAILURE_REASON + + " = ? AND " + + CallAnalyticsTable.RELEASE_VERSION + + " = ? "; + ContentValues values = getContentValues(callType, callStatus, slotId, rat, failureReason); + String[] selectionArgs = { + values.getAsString(CallAnalyticsTable.LOG_DATE), + values.getAsString(CallAnalyticsTable.CALL_STATUS), + values.getAsString(CallAnalyticsTable.CALL_TYPE), + values.getAsString(CallAnalyticsTable.SLOT_ID), + values.getAsString(CallAnalyticsTable.RAT), + values.getAsString(CallAnalyticsTable.FAILURE_REASON), + values.getAsString(CallAnalyticsTable.RELEASE_VERSION) + }; + whenConditionForGetCursor(); + mCallAnalyticsProvider.insertDataToDb(callType, callStatus, slotId, rat, failureReason); + verifyForGetCursor(mCallInsertionProjection, callFailedInsertionSelection, selectionArgs); + } + + public void setUpTestForUpdateEntryIfExistsOrInsert() throws NoSuchMethodException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + mContentValues = new ContentValues(); + mContentValues.put(CallAnalyticsTable.CALL_STATUS, "Success"); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenCursorNull() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + updateEntryIfExistsOrInsert.invoke(mCallAnalyticsProvider, null, values); + verify(mTelephonyAnalyticsUtil).insert(eq(CallAnalyticsTable.TABLE_NAME), eq(values)); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenCursorInvalid() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + when(mCursor.moveToFirst()).thenReturn(false); + updateEntryIfExistsOrInsert.invoke(mCallAnalyticsProvider, mCursor, values); + verify(mTelephonyAnalyticsUtil).insert(eq(CallAnalyticsTable.TABLE_NAME), eq(values)); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenCursorValidUpdateSuccess() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(CallAnalyticsTable._ID)).thenReturn(0 /* idColumnIndex */); + when(mCursor.getColumnIndex(CallAnalyticsTable.COUNT)).thenReturn(1 /* countColumnIndex */); + when(mCursor.getInt(0 /* idColumnIndex */)).thenReturn(100 /* id */); + when(mCursor.getInt(1 /* countColumnIndex */)).thenReturn(5 /* count*/); + + String updateSelection = CallAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {String.valueOf(100 /* id */)}; + + updateEntryIfExistsOrInsert.invoke(mCallAnalyticsProvider, mCursor, values); + + values.put(CallAnalyticsTable.COUNT, 6 /* newCount */); + verify(mTelephonyAnalyticsUtil) + .update( + eq(CallAnalyticsTable.TABLE_NAME), + eq(values), + eq(updateSelection), + eq(updateSelectionArgs)); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToInvalidIdIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(CallAnalyticsTable._ID)).thenReturn(-1 /* idColumnIndex */); + when(mCursor.getColumnIndex(CallAnalyticsTable.COUNT)).thenReturn(1 /* countColumnIndex */); + updateEntryIfExistsOrInsert.invoke(mCallAnalyticsProvider, mCursor, values); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToInvalidCountIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(CallAnalyticsTable._ID)).thenReturn(0 /* idColumnIndex */); + when(mCursor.getColumnIndex(CallAnalyticsTable.COUNT)) + .thenReturn(-1 /* countColumnIndex */); + updateEntryIfExistsOrInsert.invoke(mCallAnalyticsProvider, mCursor, values); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToInvalidColumnIndex() + throws NoSuchMethodException { + Method updateEntryIfExistsOrInsert = + CallAnalyticsProvider.class.getDeclaredMethod( + "updateEntryIfExistsOrInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + + ContentValues values = new ContentValues(); + values.put(CallAnalyticsTable.CALL_STATUS, "Success"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(CallAnalyticsTable._ID)).thenReturn(-1 /* idColumnIndex */); + when(mCursor.getColumnIndex(CallAnalyticsTable.COUNT)) + .thenReturn(-1 /* countColumnIndex */); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @After + public void tearDown() { + mCallAnalyticsProvider = null; + mContentValues = null; + mTelephonyAnalyticsUtil = null; + mCursor = null; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/analytics/ServiceStateAnalyticsProviderTest.java b/tests/telephonytests/src/com/android/internal/telephony/analytics/ServiceStateAnalyticsProviderTest.java new file mode 100644 index 0000000000..dcc1c737b1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/analytics/ServiceStateAnalyticsProviderTest.java @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.ServiceStateAnalyticsTable; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; + +public class ServiceStateAnalyticsProviderTest { + @Mock TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + @Mock Cursor mCursor; + @Mock TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState mState; + private ContentValues mContentValues; + + final int mSlotIndex = 0; + ServiceStateAnalyticsProvider mServiceStateAnalyticsProvider; + final String mCreateServiceStateTableQuery = + "CREATE TABLE IF NOT EXISTS " + + ServiceStateAnalyticsTable.TABLE_NAME + + " ( " + + ServiceStateAnalyticsTable._ID + + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ServiceStateAnalyticsTable.LOG_DATE + + " DATE ," + + ServiceStateAnalyticsTable.SLOT_ID + + " INTEGER , " + + ServiceStateAnalyticsTable.TIME_DURATION + + " INTEGER ," + + ServiceStateAnalyticsTable.RAT + + " TEXT ," + + ServiceStateAnalyticsTable.DEVICE_STATUS + + " TEXT ," + + ServiceStateAnalyticsTable.RELEASE_VERSION + + " TEXT " + + ");"; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + assert (mTelephonyAnalyticsUtil != null); + mServiceStateAnalyticsProvider = + new ServiceStateAnalyticsProvider(mTelephonyAnalyticsUtil, mSlotIndex); + verify(mTelephonyAnalyticsUtil).createTable(mCreateServiceStateTableQuery); + mContentValues = getDummyContentValue(); + } + + @Test + public void valid() { + assert (mServiceStateAnalyticsProvider != null); + assert (mTelephonyAnalyticsUtil != null); + assert (mCursor != null); + assert (mState != null); + } + + @Test + public void testInsertDataToDb() { + TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState lastState = + new TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState( + 0 /*slotIndex*/, + "LTE" /*rat*/, + "IN_SERVICE" /*deviceStatus*/, + 233423424 /*timestampStart*/); + ContentValues values = new ContentValues(); + long timeInterval = 343443434 /*endTimeStamp*/ - lastState.getTimestampStart(); + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(ServiceStateAnalyticsTable.LOG_DATE, dateToday); + values.put(ServiceStateAnalyticsTable.TIME_DURATION, timeInterval); + values.put(ServiceStateAnalyticsTable.SLOT_ID, lastState.getSlotIndex()); + values.put(ServiceStateAnalyticsTable.RAT, lastState.getRAT()); + values.put(ServiceStateAnalyticsTable.DEVICE_STATUS, lastState.getDeviceStatus()); + values.put(ServiceStateAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + + final String[] serviceStateInsertionColumns = { + ServiceStateAnalyticsTable._ID, ServiceStateAnalyticsTable.TIME_DURATION + }; + final String serviceStateInsertionSelection = + ServiceStateAnalyticsTable.LOG_DATE + + " = ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? AND " + + ServiceStateAnalyticsTable.RAT + + " = ? AND " + + ServiceStateAnalyticsTable.DEVICE_STATUS + + " = ? AND " + + ServiceStateAnalyticsTable.RELEASE_VERSION + + " = ? "; + final String[] selectionArgs = { + values.getAsString(ServiceStateAnalyticsTable.LOG_DATE), + values.getAsString(ServiceStateAnalyticsTable.SLOT_ID), + values.getAsString(ServiceStateAnalyticsTable.RAT), + values.getAsString(ServiceStateAnalyticsTable.DEVICE_STATUS), + values.getAsString(ServiceStateAnalyticsTable.RELEASE_VERSION) + }; + when(mTelephonyAnalyticsUtil.getCursor( + anyString(), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + mServiceStateAnalyticsProvider.insertDataToDb(lastState, 343443434 /*endTimeStamp*/); + + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(serviceStateInsertionColumns), + eq(serviceStateInsertionSelection), + eq(selectionArgs), + isNull(), + isNull(), + isNull(), + isNull()); + } + + private Method setReflectionForTestingUpdateEntryIfExistsOrInsert() + throws NoSuchMethodException { + Method updateEntryIfExistsOrInsert = + ServiceStateAnalyticsProvider.class.getDeclaredMethod( + "updateIfEntryExistsOtherwiseInsert", Cursor.class, ContentValues.class); + updateEntryIfExistsOrInsert.setAccessible(true); + return updateEntryIfExistsOrInsert; + } + + private ContentValues getDummyContentValue() { + ContentValues values = new ContentValues(); + values.put(ServiceStateAnalyticsTable.DEVICE_STATUS, "IN_SERVICE" /*DeviceStatus*/); + values.put(ServiceStateAnalyticsTable.TIME_DURATION, 423234 /*Time Duration*/); + return values; + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenCursorNull() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, null, mContentValues); + verify(mTelephonyAnalyticsUtil) + .insert(eq(ServiceStateAnalyticsTable.TABLE_NAME), eq(mContentValues)); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWhenEntryNotExist() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + when(mCursor.moveToFirst()).thenReturn(false); + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, null, mContentValues); + verify(mTelephonyAnalyticsUtil) + .insert(eq(ServiceStateAnalyticsTable.TABLE_NAME), eq(mContentValues)); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenCursorValidAndUpdateSuccess() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable._ID)).thenReturn(0 /* idIndex */); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.TIME_DURATION)) + .thenReturn(1 /* timeDurationIndex */); + when(mCursor.getInt(0 /* idIndex */)).thenReturn(100 /* ID */); + when(mCursor.getInt(1 /* timeDurationIndex */)).thenReturn(523535 /* oldTimeDuration */); + + String updateSelection = ServiceStateAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {Integer.toString(100 /* ID */)}; + + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, mCursor, mContentValues); + mContentValues.put( + ServiceStateAnalyticsTable.TIME_DURATION, 946769 /* updatedTimeDuration */); + verify(mTelephonyAnalyticsUtil) + .update( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(mContentValues), + eq(updateSelection), + eq(updateSelectionArgs)); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToInvalidIdIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable._ID)).thenReturn(-1 /* idIndex */); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.TIME_DURATION)) + .thenReturn(1 /* timeDurationIndex */); + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, mCursor, mContentValues); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToInvalidDurationIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable._ID)).thenReturn(0 /* idIndex */); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.TIME_DURATION)) + .thenReturn(-1 /* timeDurationIndex */); + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, mCursor, mContentValues); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateEntryIfExistsOrInsertWhenUpdateFailedDueToAllInvalidIndex() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Method updateEntryIfExistsOrInsert = setReflectionForTestingUpdateEntryIfExistsOrInsert(); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable._ID)).thenReturn(-1 /* idIndex */); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.TIME_DURATION)) + .thenReturn(-1 /* timeDurationIndex */); + updateEntryIfExistsOrInsert.invoke(mServiceStateAnalyticsProvider, mCursor, mContentValues); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + private void setWhenClauseForGetCursor( + String[] columns, String selection, String[] selectionArgs) { + when(mTelephonyAnalyticsUtil.getCursor( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(columns), + eq(selection), + eq(selectionArgs), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + } + + private void verifyClause(String[] columns, String selection, String[] selectionArgs) { + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(columns), + eq(selection), + eq(selectionArgs), + isNull(), + isNull(), + isNull(), + isNull()); + } + + private void setUpNullCursorReturn() { + when(mTelephonyAnalyticsUtil.getCursor( + anyString(), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(null); + } + + @Test + public void testTotalUpTimeThroughAggregate() { + HashMap<String, Long> empty = new HashMap<>(); + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = ServiceStateAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + setWhenClauseForGetCursor(columns, selection, selectionArgs); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getLong(0 /* columnIndex */)).thenReturn(1000000L /* upTime */); + + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + assertEquals( + actual.get(0 /* Array Index for Total Uptime*/), + "Total UpTime = " + 1000000 /* upTime */ + " millis"); + } + + @Test + public void testTotalUpTimeWhenCursorNullThroughAggregate() { + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = ServiceStateAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + setUpNullCursorReturn(); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + assertEquals( + actual.get(0 /* Array Index for Total Uptime*/), + "Total UpTime = " + 0 /*upTime */ + " millis"); + } + + @Test + public void testTotalUpTimeWhenCursorInvalidThroughAggregate() { + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = ServiceStateAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + setWhenClauseForGetCursor(columns, selection, selectionArgs); + when(mCursor.moveToFirst()).thenReturn(false); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + assertEquals( + actual.get(0 /* Array Index for Total Uptime*/), + "Total UpTime = " + 0 /*upTime */ + " millis"); + } + + @Test + public void testOutOfServiceDurationThroughAggregate() { + setUpTotalTime(); + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? " + + " AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + + when(mCursor.moveToFirst()).thenReturn(true, true); + when(mCursor.getLong(0 /*columnIndex*/)) + .thenReturn(1000000L /*totalUpTime*/, 100000L /*outOfServiceTime*/); + setWhenClauseForGetCursor(columns, selection, selectionArgs); + + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + assertEquals( + actual.get(1), + "Out of Service Time = " + + 100000 /*outOfServiceTime*/ + + " millis, Percentage " + + "10.00" + + "%"); + } + + @Test + public void testOutOfServiceDurationWhenCursorNullThroughAggregate() { + HashMap<String, Long> empty = new HashMap<>(); + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? " + + " AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + setUpNullCursorReturn(); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + boolean check = + actual.get(1 /* ArrayIndex for Out Of Service Time Info */) + .contains("Out of Service Time = 0"); + assertTrue(check); + } + + @Test + public void testOutOfServiceDurationWhenCursorInvalidThroughAggregate() { + HashMap<String, Long> empty = new HashMap<>(); + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? " + + " AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + setWhenClauseForGetCursor(columns, selection, selectionArgs); + when(mCursor.moveToFirst()).thenReturn(false); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyClause(columns, selection, selectionArgs); + boolean check = actual.get(1).contains("Out of Service Time = 0"); + assertTrue(check); + } + + private void whenClauseForGroupByPresent( + String[] columns, String selection, String[] selectionArgs, String groupBy) { + when(mTelephonyAnalyticsUtil.getCursor( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(columns), + eq(selection), + eq(selectionArgs), + eq(groupBy), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + } + + private void verifyGroupBy( + String[] columns, String selection, String[] selectionArgs, String groupBy) { + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(ServiceStateAnalyticsTable.TABLE_NAME), + eq(columns), + eq(selection), + eq(selectionArgs), + eq(groupBy), + isNull(), + isNull(), + isNull()); + } + + private void setUpTotalTime() { + String[] columns = {"SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ")"}; + String selection = ServiceStateAnalyticsTable.SLOT_ID + " = ? "; + String[] selectionArgs = {Integer.toString(mSlotIndex)}; + setWhenClauseForGetCursor(columns, selection, selectionArgs); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getLong(0 /*columnIndex*/)).thenReturn(1000000L /*upTime*/); + } + + @Test + public void testOutOfServiceDurationByReasonWhenValid() { + setUpTotalTime(); + String[] columns = { + ServiceStateAnalyticsTable.DEVICE_STATUS, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.DEVICE_STATUS; + whenClauseForGroupByPresent(columns, selection, selectionArgs, groupBy); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.DEVICE_STATUS)) + .thenReturn(0 /*deviceStatusIndex*/); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /*totalTimeIndex*/); + when(mCursor.moveToNext()).thenReturn(true, false); + when(mCursor.getString(0 /*deviceStatusIndex*/)).thenReturn("NO_NETWORK" /*oosReason*/); + when(mCursor.getLong(1 /*totalTimeIndex*/)).thenReturn(100000L /*oosTime*/); + + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyGroupBy(columns, selection, selectionArgs, groupBy); + assertEquals( + actual.get(2 /*oosReasonDumpArrayIndex*/), + "Out of service Reason = " + "NO_NETWORK" + ", Percentage = " + "10.00" + "%"); + } + + @Test + public void testOutOfServiceDurationByReasonWhenNoDataInCursor() { + String[] columns = { + ServiceStateAnalyticsTable.DEVICE_STATUS, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.DEVICE_STATUS; + HashMap<String, Long> outOfServiceDurationByReason = new HashMap<>(); + outOfServiceDurationByReason.put("NO_NETWORK", 10000L); + + whenClauseForGroupByPresent(columns, selection, selectionArgs, groupBy); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.DEVICE_STATUS)) + .thenReturn(0 /*deviceStatusIndex*/); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /*totalTimeIndex*/); + when(mCursor.moveToNext()).thenReturn(false); + + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyGroupBy(columns, selection, selectionArgs, groupBy); + assertEquals(actual.size(), 2 /*expectedArraySize*/); + } + + @Test + public void testOutOfServiceDurationByReasonWhenReasonIndexInvalid() { + String[] columns = { + ServiceStateAnalyticsTable.DEVICE_STATUS, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.DEVICE_STATUS; + HashMap<String, Long> outOfServiceDurationByReason = new HashMap<>(); + outOfServiceDurationByReason.put("NO_NETWORK", 10000L); + + whenClauseForGroupByPresent(columns, selection, selectionArgs, groupBy); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.DEVICE_STATUS)) + .thenReturn(-1 /*deviceStatusIndex*/); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /*totalTimeIndex*/); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyGroupBy(columns, selection, selectionArgs, groupBy); + assertEquals(actual.size(), 2 /*expectedArraySize*/); + } + + @Test + public void testOutOfServiceDurationByReasonWhenTimeIndexInvalid() { + String[] columns = { + ServiceStateAnalyticsTable.DEVICE_STATUS, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.DEVICE_STATUS + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"IN_SERVICE", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.DEVICE_STATUS; + HashMap<String, Long> outOfServiceDurationByReason = new HashMap<>(); + outOfServiceDurationByReason.put("NO_NETWORK", 10000L); + + whenClauseForGroupByPresent(columns, selection, selectionArgs, groupBy); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.DEVICE_STATUS)) + .thenReturn(0 /*deviceStatusIndex*/); + when(mCursor.getColumnIndex("totalTime")).thenReturn(-1 /*totalTimeIndex*/); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + verifyGroupBy(columns, selection, selectionArgs, groupBy); + assertEquals(actual.size(), 2 /*expectedArraySize*/); + } + + private void setUpForTestingGetInServiceDurationByRat() { + String[] columns = { + ServiceStateAnalyticsTable.RAT, + "SUM(" + ServiceStateAnalyticsTable.TIME_DURATION + ") AS totalTime" + }; + String selection = + ServiceStateAnalyticsTable.RAT + + " != ? AND " + + ServiceStateAnalyticsTable.SLOT_ID + + " = ? "; + String[] selectionArgs = {"NA", Integer.toString(mSlotIndex)}; + String groupBy = ServiceStateAnalyticsTable.RAT; + whenClauseForGroupByPresent(columns, selection, selectionArgs, groupBy); + } + + @Test + public void testInServiceDurationByRatWhenDataPresent() { + setUpForTestingGetInServiceDurationByRat(); + setUpTotalTime(); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.RAT)).thenReturn(0 /* ratIndex */); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /* totalTimeIndex */); + when(mCursor.moveToNext()).thenReturn(true, false); + when(mCursor.getString(0 /* ratIndex */)).thenReturn("LTE" /* inServiceRat */); + when(mCursor.getLong(1 /* totalTimeIndex */)).thenReturn(200000L /* inServiceTime */); + + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + assertEquals( + actual.get(2 /*arrayIndex For In Service RAT Information */), + "IN_SERVICE RAT : " + "LTE" + ", Percentage = 20.00" + "%"); + } + + @Test + public void testInServiceDurationByRatWhenDataNotPresent() { + setUpForTestingGetInServiceDurationByRat(); + setUpTotalTime(); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.RAT)).thenReturn(0 /* ratIndex */); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /* totalTimeIndex */); + when(mCursor.moveToNext()).thenReturn(false); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + assertEquals(actual.size(), 2 /* expectedArraySize */); + } + + @Test + public void testInServiceDurationByRatWhenInvalidRatIndex() { + setUpForTestingGetInServiceDurationByRat(); + setUpTotalTime(); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.RAT)).thenReturn(-1 /* ratIndex */); + when(mCursor.getColumnIndex("totalTime")).thenReturn(1 /* totalTimeIndex */); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + assertEquals(actual.size(), 2 /* expectedArraySize */); + } + + @Test + public void testInServiceDurationByRatWhenInvalidTimeIndex() { + setUpForTestingGetInServiceDurationByRat(); + setUpTotalTime(); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.RAT)).thenReturn(0 /* ratIndex */); + when(mCursor.getColumnIndex("totalTime")).thenReturn(-1 /* totalTimeIndex */); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + assertEquals(actual.size(), 2 /* expectedArraySize */); + } + + @Test + public void testInServiceDurationByRatWhenBothIndexInvalid() { + setUpForTestingGetInServiceDurationByRat(); + setUpTotalTime(); + when(mCursor.getColumnIndex(ServiceStateAnalyticsTable.RAT)).thenReturn(-1 /* ratIndex */); + when(mCursor.getColumnIndex("totalTime")).thenReturn(-1 /* totalTimeIndex */); + ArrayList<String> actual = mServiceStateAnalyticsProvider.aggregate(); + assertEquals(actual.size(), 2 /* expectedArraySize */); + } + + @Test + public void testDeleteOldAndOverflowDataWhenLastDeletedDateEqualsToday() { + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + mServiceStateAnalyticsProvider.setDateOfDeletedRecordsServiceStateTable(dateToday); + TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState + mockTimeStampedServiceState = + mock( + TelephonyAnalytics.ServiceStateAnalytics.TimeStampedServiceState + .class); + mServiceStateAnalyticsProvider.insertDataToDb( + mockTimeStampedServiceState, 100L /* endTimeStamp */); + } + + @After + public void tearDown() { + mServiceStateAnalyticsProvider = null; + mCursor = null; + mTelephonyAnalyticsUtil = null; + mContentValues = null; + mState = null; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/analytics/SmsMmsAnalyticsProviderTest.java b/tests/telephonytests/src/com/android/internal/telephony/analytics/SmsMmsAnalyticsProviderTest.java new file mode 100644 index 0000000000..54acfebccb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/analytics/SmsMmsAnalyticsProviderTest.java @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.analytics; + +import static android.os.Build.VERSION.INCREMENTAL; + +import static com.android.internal.telephony.analytics.TelephonyAnalyticsDatabase.DATE_FORMAT; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.ContentValues; +import android.database.Cursor; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.concurrent.CountDownLatch; + +public class SmsMmsAnalyticsProviderTest { + @Mock TelephonyAnalyticsUtil mTelephonyAnalyticsUtil; + + SmsMmsAnalyticsProvider mSmsMmsAnalyticsProvider; + private TelephonyAnalyticsUtil mMockTelephonyAnalyticsUtil; + private static final String[] SMS_MMS_INSERTION_PROJECTION = { + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable._ID, + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.COUNT + }; + + @Mock Cursor mCursor; + final String mCreateTableQuery = + "CREATE TABLE IF NOT EXISTS SmsMmsDataLogs(" + + "_id INTEGER PRIMARY KEY," + + "LogDate DATE ," + + "SmsMmsStatus TEXT DEFAULT ''," + + "SmsMmsType TEXT DEFAULT ''," + + "SlotID INTEGER , " + + "RAT TEXT DEFAULT ''," + + "FailureReason TEXT DEFAULT ''," + + "ReleaseVersion TEXT DEFAULT '' , " + + "Count INTEGER DEFAULT 1 );"; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSmsMmsAnalyticsProvider = new SmsMmsAnalyticsProvider(mTelephonyAnalyticsUtil, 0); + mMockTelephonyAnalyticsUtil = mock(TelephonyAnalyticsUtil.class); + verify(mTelephonyAnalyticsUtil).createTable(mCreateTableQuery); + } + + @Test + public void testCursor() { + assert (mCursor != null); + assert (mTelephonyAnalyticsUtil != null); + } + + private ContentValues getContentValues( + String status, String type, String rat, String failureReason) { + ContentValues values = new ContentValues(); + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.LOG_DATE, dateToday); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_STATUS, status); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_TYPE, type); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT, rat); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SLOT_ID, 0); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.FAILURE_REASON, failureReason); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RELEASE_VERSION, INCREMENTAL); + + return values; + } + + private void mockAndVerifyCall(String selection, String[] selectionArgs) { + when(mTelephonyAnalyticsUtil.getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mCursor); + + verify(mTelephonyAnalyticsUtil) + .getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + eq(SMS_MMS_INSERTION_PROJECTION), + eq(selection), + eq(selectionArgs), + isNull(), + isNull(), + isNull(), + isNull()); + } + + @Test + public void testFailureSms() { + String status = "Failure"; + String type = "SMS Outgoing"; + String rat = "LTE"; + String failureReason = "SIM_ABSENT"; + final String smsMmsInsertionFailureSelection = + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.LOG_DATE + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SLOT_ID + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.FAILURE_REASON + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RELEASE_VERSION + + " = ? "; + ContentValues values = getContentValues(status, type, rat, failureReason); + + String[] selectionArgs = + new String[] { + values.getAsString(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.LOG_DATE), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_STATUS), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_TYPE), + values.getAsString(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT), + values.getAsString(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SLOT_ID), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.FAILURE_REASON), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RELEASE_VERSION) + }; + mSmsMmsAnalyticsProvider.insertDataToDb(status, type, rat, failureReason); + mockAndVerifyCall(smsMmsInsertionFailureSelection, selectionArgs); + } + + @Test + public void testSuccessSms() { + String status = "Success"; + String type = "SMS Outgoing"; + String rat = "LTE"; + String failureReason = "SIM_ABSENT"; + + final String smsMmsInsertionSuccessSelection = + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.LOG_DATE + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_TYPE + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_STATUS + + " = ? AND " + + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SLOT_ID + + " = ? "; + + ContentValues values = getContentValues(status, type, rat, failureReason); + String[] selectionArgs = + new String[] { + values.getAsString(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.LOG_DATE), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_TYPE), + values.getAsString( + TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SMS_MMS_STATUS), + values.getAsString(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.SLOT_ID) + }; + + mSmsMmsAnalyticsProvider.insertDataToDb(status, type, rat, failureReason); + + mockAndVerifyCall(smsMmsInsertionSuccessSelection, selectionArgs); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWhenEntryNotExist() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.COUNT, 5); + when(mCursor.moveToFirst()).thenReturn(false); + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(mCursor, values); + verify(mTelephonyAnalyticsUtil) + .insert(eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), eq(values)); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWhenCursorNull() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.COUNT, 5); + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(null, values); + verify(mTelephonyAnalyticsUtil) + .insert(eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), eq(values)); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWhenEntryExists() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT, "LTE"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex("_id")).thenReturn(0); + when(mCursor.getColumnIndex("Count")).thenReturn(1); + when(mCursor.getInt(0)).thenReturn(100); + when(mCursor.getInt(1)).thenReturn(2); + + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(mCursor, values); + + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.COUNT, 3); + + String updateSelection = TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable._ID + " = ? "; + String[] updateSelectionArgs = {String.valueOf(100)}; + + verify(mTelephonyAnalyticsUtil) + .update( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + eq(values), + eq(updateSelection), + eq(updateSelectionArgs)); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWithInvalidIdColumnIndex() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT, "LTE"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex("_id")).thenReturn(-1); + when(mCursor.getColumnIndex("Count")).thenReturn(1); + when(mCursor.getInt(0)).thenReturn(100); + when(mCursor.getInt(1)).thenReturn(2); + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(mCursor, values); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWithInvalidCountColumnIndex() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT, "LTE"); + + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex("_id")).thenReturn(0); + when(mCursor.getColumnIndex("Count")).thenReturn(-1); + when(mCursor.getInt(0)).thenReturn(100); + when(mCursor.getInt(1)).thenReturn(2); + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(mCursor, values); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testUpdateIfEntryExistsOtherwiseInsertWithInvalidColumnIndex() { + ContentValues values = new ContentValues(); + values.put(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.RAT, "LTE"); + when(mCursor.moveToFirst()).thenReturn(true); + when(mCursor.getColumnIndex("_id")).thenReturn(-1); + when(mCursor.getColumnIndex("Count")).thenReturn(-1); + when(mCursor.getInt(0)).thenReturn(100); + when(mCursor.getInt(1)).thenReturn(2); + mSmsMmsAnalyticsProvider.updateIfEntryExistsOtherwiseInsert(mCursor, values); + verifyNoMoreInteractions(mTelephonyAnalyticsUtil); + } + + @Test + public void testDeleteWhenDateEqualsToday() { + String status = "Success"; + String type = "SMS Outgoing"; + String rat = "LTE"; + String failureReason = "SIM_ABSENT"; + + String dateToday = DATE_FORMAT.format(Calendar.getInstance().toInstant()); + mSmsMmsAnalyticsProvider.setDateOfDeletedRecordsSmsMmsTable(dateToday); + mSmsMmsAnalyticsProvider.insertDataToDb(status, type, rat, failureReason); + verify(mTelephonyAnalyticsUtil, times(0)) + .delete(anyString(), anyString(), any(String[].class)); + } + + @Test + public void testDeleteWhenDateNotNullAndNotEqualsToday() { + String status = "Success"; + String type = "SMS Outgoing"; + String rat = "LTE"; + String failureReason = "SIM_ABSENT"; + String dateToday = "1965-10-12"; + mSmsMmsAnalyticsProvider.setDateOfDeletedRecordsSmsMmsTable(dateToday); + mSmsMmsAnalyticsProvider.insertDataToDb(status, type, rat, failureReason); + verify(mTelephonyAnalyticsUtil, times(1)) + .deleteOverflowAndOldData(anyString(), anyString(), anyString()); + } + + @Test + public void testAggregate() throws NoSuchFieldException, IllegalAccessException { + final CountDownLatch latch = new CountDownLatch(9); + Cursor mockCursor = mock(Cursor.class); + when(mMockTelephonyAnalyticsUtil.getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull())) + .thenReturn(mockCursor); + when(mMockTelephonyAnalyticsUtil.getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + anyString(), + isNull(), + isNull(), + isNull())) + .thenReturn(mockCursor); + when(mMockTelephonyAnalyticsUtil.getCountFromCursor(eq(mockCursor))) + .thenReturn( + 80L /*totalOutgoingSms*/, + 70L /*totalIncomingSms*/, + 60L /*totalOutgoingMms*/, + 50L /*totalIncomingMms*/, + 40L /*totalFailedOutgoingSms*/, + 30L /*totalFailedIncomingSms*/, + 20L /*totalFailedOutgoingMms*/, + 10L /*totalFailedIncomingMms*/); + + when(mockCursor.getColumnIndex("RAT")).thenReturn(0 /*ratIndex*/); + when(mockCursor.getColumnIndex("count")).thenReturn(1 /*countIndex*/); + when(mockCursor.moveToNext()).thenReturn(true, false); + when(mockCursor.getString(0 /*ratIndex*/)).thenReturn("LTE" /* RAT*/); + when(mockCursor.getInt(1 /*countIndex*/)).thenReturn(10 /* Count */); + + SmsMmsAnalyticsProvider smsMmsAnalyticsProvider = + new SmsMmsAnalyticsProvider(mMockTelephonyAnalyticsUtil, 0 /* slotIndex */); + ArrayList<String> received = smsMmsAnalyticsProvider.aggregate(); + + verify(mMockTelephonyAnalyticsUtil, times(8)) + .getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + isNull(), + isNull(), + isNull(), + isNull()); + verify(mMockTelephonyAnalyticsUtil, times(1)) + .getCursor( + eq(TelephonyAnalyticsDatabase.SmsMmsAnalyticsTable.TABLE_NAME), + any(String[].class), + anyString(), + any(String[].class), + anyString(), + isNull(), + isNull(), + isNull()); + verify(mMockTelephonyAnalyticsUtil, times(8)).getCountFromCursor(eq(mockCursor)); + verify(mockCursor).getColumnIndex("RAT"); + verify(mockCursor).getColumnIndex("count"); + + assertEquals( + "Total Outgoing Sms Count = 80", + received.get(0 /* array index for totalOutgoingSms */)); + assertEquals( + "Total Incoming Sms Count = 70", + received.get(1 /* array index for totalIncomingSms */)); + assertEquals( + "Failed Outgoing SMS Count = 40 Percentage failure rate for Outgoing SMS :50.00%", + received.get(2 /* array index for totalFailedOutgoingSms */)); + assertEquals( + "Failed Incoming SMS Count = 30 Percentage failure rate for Incoming SMS :42.86%", + received.get(3 /* array index for totalFailedIncomingSms */)); + assertEquals( + "Overall Fail Percentage = 46.67%", + received.get(4 /* array index for overall fail percentage */)); + assertEquals( + "Failed SMS Count for RAT : LTE = 10, Percentage = 6.67%", + received.get(5 /* array index for failedSmsTypeCountByRat */)); + } + + @After + public void tearDown() { + mCursor = null; + mTelephonyAnalyticsUtil = null; + mMockTelephonyAnalyticsUtil = null; + mSmsMmsAnalyticsProvider = null; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java index 4d116a8553..91ed03f50c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -41,11 +42,13 @@ import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.NetworkService; import android.telephony.data.ApnSetting; +import android.telephony.data.DataServiceCallback; import android.telephony.data.IQualifiedNetworksService; import android.telephony.data.IQualifiedNetworksServiceCallback; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; @@ -55,6 +58,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class AccessNetworksManagerTest extends TelephonyTest { @@ -68,8 +76,37 @@ public class AccessNetworksManagerTest extends TelephonyTest { // The real callback passed created by AccessNetworksManager. private IQualifiedNetworksServiceCallback.Stub mQnsCallback; - private PersistableBundle mBundle; + private List<Integer> mIIntegerConsumerResults = new ArrayList<>(); + private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0); + private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("mIIntegerConsumer: result=" + result); + mIIntegerConsumerResults.add(result); + try { + mIIntegerConsumerSemaphore.release(); + } catch (Exception ex) { + logd("mIIntegerConsumer: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + private boolean waitForIIntegerConsumerResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIIntegerConsumerSemaphore.tryAcquire(500 /* Timeout */, + TimeUnit.MILLISECONDS)) { + logd("Timeout to receive IIntegerConsumer() callback"); + return false; + } + } catch (Exception ex) { + logd("waitForIIntegerConsumerResult: Got exception=" + ex); + return false; + } + } + return true; + } private void addQnsService() throws Exception { ServiceInfo QnsInfo = new ServiceInfo(); @@ -116,7 +153,8 @@ public class AccessNetworksManagerTest extends TelephonyTest { }).when(mMockedCallback).invokeFromExecutor(any(Runnable.class)); mMockedDataConfigManager = Mockito.mock(DataConfigManager.class); - mAccessNetworksManager = new AccessNetworksManager(mPhone, Looper.myLooper()); + mAccessNetworksManager = + new AccessNetworksManager(mPhone, Looper.myLooper(), mFeatureFlags); processAllMessages(); replaceInstance(AccessNetworksManager.class, "mDataConfigManager", @@ -281,6 +319,33 @@ public class AccessNetworksManagerTest extends TelephonyTest { assertThat(mAccessNetworksManager.getPreferredTransportByNetworkCapability( NetworkCapabilities.NET_CAPABILITY_XCAP)).isEqualTo( AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + } + + @Test + public void testRequestNetworkValidation_WithFlagEnabled() throws Exception { + when(mFeatureFlags.networkValidation()).thenReturn(true); + mQnsCallback.onNetworkValidationRequested(NetworkCapabilities.NET_CAPABILITY_IMS, + mIIntegerConsumer); + processAllMessages(); + assertThat(waitForIIntegerConsumerResult(1 /*numOfEvents*/)).isFalse(); + } + + @Test + public void testRequestNetworkValidation_WithFlagDisabled() throws Exception { + mIIntegerConsumerResults.clear(); + when(mFeatureFlags.networkValidation()).thenReturn(false); + + mQnsCallback.onNetworkValidationRequested(NetworkCapabilities.NET_CAPABILITY_IMS, + mIIntegerConsumer); + processAllMessages(); + + assertThat(waitForIIntegerConsumerResult(1 /*numOfEvents*/)).isTrue(); + assertThat((long) mIIntegerConsumerResults.get(0)) + .isEqualTo(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + verify(mDataNetworkController, never()).requestNetworkValidation( + NetworkCapabilities.NET_CAPABILITY_IMS, + mIntegerConsumer); } + } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index b6d77e952e..378df4b944 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -16,6 +16,9 @@ package com.android.internal.telephony.data; +import static android.telephony.data.ApnSetting.INFRASTRUCTURE_CELLULAR; +import static android.telephony.data.ApnSetting.INFRASTRUCTURE_SATELLITE; + import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -154,6 +157,9 @@ public class ApnSettingTest extends TelephonyTest { assertTrue(createApnSetting( ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_EMERGENCY) .canHandleType(ApnSetting.TYPE_EMERGENCY)); + assertTrue(createApnSetting( + ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_RCS | ApnSetting.TYPE_EMERGENCY) + .canHandleType(ApnSetting.TYPE_RCS)); assertFalse(createApnSetting(ApnSetting.TYPE_ALL) .canHandleType(ApnSetting.TYPE_MCX)); assertTrue(createApnSetting( @@ -378,4 +384,34 @@ public class ApnSettingTest extends TelephonyTest { .build(); assertEquals("proxy.mobile.att.net", apn3.getMmsProxyAddressAsString()); } + + @Test + public void testBuild_InfrastructureBitmask() { + int infrastructureBitmask = INFRASTRUCTURE_CELLULAR | INFRASTRUCTURE_SATELLITE; + ApnSetting apn1 = new ApnSetting.Builder() + .setId(1234) + .setOperatorNumeric("310260") + .setEntryName("mms") + .setApnName("mms") + .setApnTypeBitmask(ApnSetting.TYPE_MMS | ApnSetting.TYPE_DEFAULT) + .setProtocol(ApnSetting.PROTOCOL_IPV4V6) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE)) + .build(); + // InfrastructureBitmask default value set to '3(cellular|satellite)' + assertEquals(infrastructureBitmask, apn1.getInfrastructureBitmask()); + + infrastructureBitmask = INFRASTRUCTURE_CELLULAR; + ApnSetting apn2 = new ApnSetting.Builder() + .setId(1235) + .setOperatorNumeric("310260") + .setEntryName("mms") + .setApnName("mms") + .setApnTypeBitmask(ApnSetting.TYPE_MMS | ApnSetting.TYPE_DEFAULT) + .setProtocol(ApnSetting.PROTOCOL_IPV4V6) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE)) + .setInfrastructureBitmask(infrastructureBitmask) + .build(); + // InfrastructureBitmask value set to '1(cellular)' + assertEquals(infrastructureBitmask, apn2.getInfrastructureBitmask()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java index 7ac3a170ad..6462d73bf9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AutoDataSwitchControllerTest.java @@ -21,6 +21,7 @@ import static android.telephony.SubscriptionManager.DEFAULT_PHONE_INDEX; import static com.android.internal.telephony.data.AutoDataSwitchController.EVALUATION_REASON_DATA_SETTINGS_CHANGED; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; @@ -40,8 +41,11 @@ import android.os.Message; import android.telephony.AccessNetworkConstants; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -69,14 +73,24 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { private static final int PHONE_2 = 1; private static final int SUB_2 = 2; private static final int MAX_RETRY = 5; + private static final int SCORE_TOLERANCE = 100; + private static final int GOOD_RAT_SIGNAL_SCORE = 200; + private static final int BAD_RAT_SIGNAL_SCORE = 50; // Mocked private AutoDataSwitchController.AutoDataSwitchControllerCallback mMockedPhoneSwitcherCallback; + // Real + private TelephonyDisplayInfo mGoodTelephonyDisplayInfo; + private TelephonyDisplayInfo mBadTelephonyDisplayInfo; private int mDefaultDataSub; private AutoDataSwitchController mAutoDataSwitchControllerUT; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mGoodTelephonyDisplayInfo = new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, false /*roaming*/); + mBadTelephonyDisplayInfo = new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UMTS, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false /*roaming*/); mMockedPhoneSwitcherCallback = mock(AutoDataSwitchController.AutoDataSwitchControllerCallback.class); @@ -95,13 +109,19 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { doReturn(mDisplayInfoController).when(phone).getDisplayInfoController(); doReturn(mSignalStrengthController).when(phone).getSignalStrengthController(); doReturn(mSignalStrength).when(phone).getSignalStrength(); + doReturn(mDataNetworkController).when(phone).getDataNetworkController(); + doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); doAnswer(invocation -> phone.getSubId() == mDefaultDataSub) .when(phone).isUserDataEnabled(); } - doReturn(new int[mPhones.length]).when(mSubscriptionManagerService) + doReturn(new int[]{SUB_1, SUB_2}).when(mSubscriptionManagerService) .getActiveSubIdList(true); doAnswer(invocation -> { int subId = (int) invocation.getArguments()[0]; + return subId == SUB_1 ? PHONE_1 : PHONE_2; + }).when(mSubscriptionManagerService).getPhoneId(anyInt()); + doAnswer(invocation -> { + int subId = (int) invocation.getArguments()[0]; if (!SubscriptionManager.isUsableSubIdValue(subId)) return null; @@ -111,22 +131,37 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { }).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); - // Change resource overlay + // Change data config doReturn(true).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); - doReturn(1L).when(mDataConfigManager) + doReturn(10000L).when(mDataConfigManager) .getAutoDataSwitchAvailabilityStabilityTimeThreshold(); doReturn(MAX_RETRY).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry(); + doReturn(SCORE_TOLERANCE).when(mDataConfigManager).getAutoDataSwitchScoreTolerance(); + doAnswer(invocation -> { + TelephonyDisplayInfo displayInfo = (TelephonyDisplayInfo) invocation.getArguments()[0]; + SignalStrength signalStrength = (SignalStrength) invocation.getArguments()[1]; + if (displayInfo == mGoodTelephonyDisplayInfo + || signalStrength.getLevel() > SignalStrength.SIGNAL_STRENGTH_MODERATE) { + return GOOD_RAT_SIGNAL_SCORE; + } + return BAD_RAT_SIGNAL_SCORE; + }).when(mDataConfigManager).getAutoDataSwitchScore(any(TelephonyDisplayInfo.class), + any(SignalStrength.class)); setDefaultDataSubId(SUB_1); doReturn(PHONE_1).when(mPhoneSwitcher).getPreferredDataPhoneId(); mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(), - mPhoneSwitcher, mMockedPhoneSwitcherCallback); + mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback); + + doReturn(true).when(mFeatureFlags).autoSwitchAllowRoaming(); } @After public void tearDown() throws Exception { mAutoDataSwitchControllerUT = null; + mGoodTelephonyDisplayInfo = null; + mBadTelephonyDisplayInfo = null; super.tearDown(); } @@ -139,8 +174,22 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { // Verify attempting to switch verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/); - // 1. Service state becomes not ideal - primary is available again + // 1.1 Service state becomes not ideal - secondary lost its advantage score, + // but primary is OOS, so continue to switch. + clearInvocations(mMockedPhoneSwitcherCallback); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback, never()) + .onRequireCancelAnyPendingAutoSwitchValidation(); + + // 1.2 Service state becomes not ideal - secondary lost its advantage score, + // since primary is in service, no need to switch. + clearInvocations(mMockedPhoneSwitcherCallback); serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); processAllFutureMessages(); verify(mMockedPhoneSwitcherCallback).onRequireCancelAnyPendingAutoSwitchValidation(); @@ -177,13 +226,151 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { } @Test + public void testRoaming_prefer_home_over_roam() { + // DDS -> nDDS: Prefer Home over Roaming + prepareIdealUsesNonDdsCondition(); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/); + + // nDDS -> DDS: Prefer Home over Roaming + doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + true/*needValidation*/); + } + + @Test + public void testRoaming_roaming_but_roam_disabled() { + // Disable RAT + signalStrength base switching. + doReturn(-1).when(mDataConfigManager).getAutoDataSwitchScoreTolerance(); + mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(), + mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback); + + // On primary phone + // 1.1 Both roaming, user allow roaming on both phone, no need to switch. + prepareIdealUsesNonDdsCondition(); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + clearInvocations(mMockedPhoneSwitcherCallback); + + mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback, never()).onRequireValidation(anyInt(), + anyBoolean()/*needValidation*/); + + // 1.2 Both roaming, but roaming is only allowed on the backup phone. + doReturn(false).when(mPhone).getDataRoamingEnabled(); + mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/); + + // On backup phone + doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); + // 2.1 Both roaming, user allow roaming on both phone, prefer default. + doReturn(true).when(mPhone).getDataRoamingEnabled(); + mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + true/*needValidation*/); + + // 2.1 Both roaming, but roaming is only allowed on the default phone. + doReturn(false).when(mPhone2).getDataRoamingEnabled(); + mAutoDataSwitchControllerUT.evaluateAutoDataSwitch(EVALUATION_REASON_DATA_SETTINGS_CHANGED); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + false/*needValidation*/); + } + + @Test + public void testRoaming_same_roaming_condition_uses_rat_signalStrength() { + doReturn(true).when(mFeatureFlags).autoDataSwitchRatSs(); + // On primary phone + // 1. Both roaming, user allow roaming on both phone, uses RAT score to decide switch. + prepareIdealUsesNonDdsCondition(); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(PHONE_2, true/*needValidation*/); + + // On backup phone + doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); + // 2. Both roaming, user allow roaming on both phone, uses RAT score to decide switch. + signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_GREAT); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); + displayInfoChanged(PHONE_1, mGoodTelephonyDisplayInfo); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + true/*needValidation*/); + } + + @Test + public void testCancelSwitch_onPrimary_rat_signalStrength() { + // 4.1.1 Display info and signal strength on secondary phone became bad, + // but primary is still OOS, so still switch to the secondary. + prepareIdealUsesNonDdsCondition(); + processAllFutureMessages(); + clearInvocations(mMockedPhoneSwitcherCallback); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_MODERATE); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback, never()) + .onRequireCancelAnyPendingAutoSwitchValidation(); + + // 4.1.2 Display info and signal strength on secondary phone became bad, + // but primary become service, then don't switch. + prepareIdealUsesNonDdsCondition(); + processAllFutureMessages(); + clearInvocations(mMockedPhoneSwitcherCallback); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_MODERATE); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback).onRequireCancelAnyPendingAutoSwitchValidation(); + + // 4.2 Display info on default phone became good just as the secondary + prepareIdealUsesNonDdsCondition(); + processAllFutureMessages(); + clearInvocations(mMockedPhoneSwitcherCallback); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + displayInfoChanged(PHONE_1, mGoodTelephonyDisplayInfo); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback).onRequireCancelAnyPendingAutoSwitchValidation(); + + // 4.3 Signal strength on default phone became just as good as the secondary + prepareIdealUsesNonDdsCondition(); + processAllFutureMessages(); + clearInvocations(mMockedPhoneSwitcherCallback); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_GREAT); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback).onRequireCancelAnyPendingAutoSwitchValidation(); + } + + @Test public void testOnNonDdsSwitchBackToPrimary() { + // Disable Rat/SignalStrength based switch to test primary OOS based switch + doReturn(-1).when(mDataConfigManager).getAutoDataSwitchScoreTolerance(); + mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(), + mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback); doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); prepareIdealUsesNonDdsCondition(); // 1.1 service state changes - primary becomes available again, require validation serviceStateChanged(PHONE_1, - NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING/*need validate*/); + NetworkRegistrationInfo.REGISTRATION_STATE_HOME/*need validate*/); processAllFutureMessages(); verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, true/*needValidation*/); @@ -193,7 +380,7 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { // 1.2 service state changes - secondary becomes unavailable, NO need validation serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME/*need validate*/); - serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING/*no need*/); + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_DENIED/*no need*/); processAllFutureMessages(); // The later validation requirement overrides the previous verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, @@ -232,18 +419,46 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { } @Test + public void testOnNonDdsSwitchBackToPrimary_rat_signalStrength() { + doReturn(true).when(mFeatureFlags).autoDataSwitchRatSs(); + doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); + + prepareIdealUsesNonDdsCondition(); + // 4.1 Display info and signal strength on secondary phone became bad just as the default + // Expect no switch since both phone has the same score. + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback, never()).onRequireValidation(anyInt(), anyBoolean()); + + clearInvocations(mMockedPhoneSwitcherCallback); + prepareIdealUsesNonDdsCondition(); + // 4.2 Display info and signal strength on secondary phone became worse than the default. + // Expect to switch. + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_GREAT); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + true/*needValidation*/); + } + + @Test public void testCancelSwitch_onSecondary() { doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); prepareIdealUsesNonDdsCondition(); - // attempts the switch back due to secondary becomes ROAMING - serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + // attempts the switch back due to secondary not usable + serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_DENIED); processAllFutureMessages(); verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, false/*needValidation*/); // cancel the switch back attempt due to secondary back to HOME + clearInvocations(mMockedPhoneSwitcherCallback); serviceStateChanged(PHONE_2, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); processAllFutureMessages(); @@ -251,6 +466,30 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { } @Test + public void testStabilityCheckOverride() { + // Starting stability check for switching to non-DDS + prepareIdealUsesNonDdsCondition(); + processAllMessages(); + + // Switch success, but the previous stability check is still pending + doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); + + // Display info and signal strength on secondary phone became worse than the default. + // Expect to switch back, and it should override the previous stability check + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_GREAT); + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_POOR); + // process all messages include the delayed message + processAllFutureMessages(); + + verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, + true/*needValidation*/); + verify(mMockedPhoneSwitcherCallback, never()).onRequireValidation(PHONE_2, + true/*needValidation*/); + } + + @Test public void testValidationFailedRetry() { prepareIdealUsesNonDdsCondition(); @@ -267,8 +506,10 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { // Change resource overlay doReturn(false).when(mDataConfigManager) .isPingTestBeforeAutoDataSwitchRequired(); + doReturn(-1 /*Disable signal based switch for easy mock*/).when(mDataConfigManager) + .getAutoDataSwitchScoreTolerance(); mAutoDataSwitchControllerUT = new AutoDataSwitchController(mContext, Looper.myLooper(), - mPhoneSwitcher, mMockedPhoneSwitcherCallback); + mPhoneSwitcher, mFeatureFlags, mMockedPhoneSwitcherCallback); //1. DDS -> nDDS, verify callback doesn't require validation prepareIdealUsesNonDdsCondition(); @@ -278,7 +519,7 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { //2. nDDS -> DDS, verify callback doesn't require validation doReturn(PHONE_2).when(mPhoneSwitcher).getPreferredDataPhoneId(); - serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + serviceStateChanged(PHONE_1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); processAllFutureMessages(); verify(mMockedPhoneSwitcherCallback).onRequireValidation(DEFAULT_PHONE_INDEX, false/*needValidation*/); @@ -327,13 +568,59 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { eq(EVENT_SERVICE_STATE_CHANGED), eq(PHONE_2)); } + @Test + public void testSubscriptionChangedUnregister() { + // Test single SIM loaded + int modemCount = 2; + doReturn(new int[]{SUB_2}).when(mSubscriptionManagerService) + .getActiveSubIdList(true); + mAutoDataSwitchControllerUT.notifySubscriptionsMappingChanged(); + processAllMessages(); + + // Verify unregister from both slots since only 1 visible SIM is insufficient for switching + verify(mDisplayInfoController, times(modemCount)) + .unregisterForTelephonyDisplayInfoChanged(any()); + verify(mSignalStrengthController, times(modemCount)) + .unregisterForSignalStrengthChanged(any()); + verify(mSST, times(modemCount)).unregisterForServiceStateChanged(any()); + + // Test single -> Duel + clearInvocations(mDisplayInfoController, mSignalStrengthController, mSST); + doReturn(new int[]{SUB_1, SUB_2}).when(mSubscriptionManagerService) + .getActiveSubIdList(true); + mAutoDataSwitchControllerUT.notifySubscriptionsMappingChanged(); + processAllMessages(); + + // Verify register on both slots + for (int phoneId = 0; phoneId < modemCount; phoneId++) { + verify(mDisplayInfoController).registerForTelephonyDisplayInfoChanged(any(), + eq(EVENT_DISPLAY_INFO_CHANGED), eq(phoneId)); + verify(mSignalStrengthController).registerForSignalStrengthChanged(any(), + eq(EVENT_SIGNAL_STRENGTH_CHANGED), eq(phoneId)); + verify(mSST).registerForServiceStateChanged(any(), + eq(EVENT_SERVICE_STATE_CHANGED), eq(phoneId)); + } + } + + @Test + public void testRatSignalStrengthSkipEvaluation() { + // Verify the secondary phone is OOS and its score(0) is too low to justify the evaluation + displayInfoChanged(PHONE_2, mBadTelephonyDisplayInfo); + processAllFutureMessages(); + verify(mMockedPhoneSwitcherCallback, never()) + .onRequireCancelAnyPendingAutoSwitchValidation(); + verify(mMockedPhoneSwitcherCallback, never()).onRequireValidation(anyInt(), anyBoolean()); + } + /** * Trigger conditions * 1. service state changes - * 2. data setting changes + * 2. telephony display info changes + * 3. signal strength changes + * 4. data setting changes * - user toggle data * - user toggle auto switch feature - * 3. default network changes + * 5. default network changes * - current network lost * - network become active on non-cellular network */ @@ -343,16 +630,44 @@ public class AutoDataSwitchControllerTest extends TelephonyTest { serviceStateChanged(PHONE_1, NetworkRegistrationInfo .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); - // 2.1 User data enabled on primary SIM + // 2. telephony display info changes + displayInfoChanged(PHONE_2, mGoodTelephonyDisplayInfo); + displayInfoChanged(PHONE_1, mBadTelephonyDisplayInfo); + + // 3. signal strength changes + signalStrengthChanged(PHONE_2, SignalStrength.SIGNAL_STRENGTH_GREAT); + signalStrengthChanged(PHONE_1, SignalStrength.SIGNAL_STRENGTH_POOR); + + // 4.1 User data enabled on primary SIM doReturn(true).when(mPhone).isUserDataEnabled(); + doReturn(true).when(mPhone).getDataRoamingEnabled(); - // 2.2 Auto switch feature is enabled + // 4.2 Auto switch feature is enabled + doReturn(true).when(mPhone2).getDataRoamingEnabled(); doReturn(true).when(mPhone2).isDataAllowed(); - // 3.1 No default network + // 5. No default network mAutoDataSwitchControllerUT.updateDefaultNetworkCapabilities(null /*networkCapabilities*/); } + private void signalStrengthChanged(int phoneId, int level) { + SignalStrength ss = mock(SignalStrength.class); + doReturn(level).when(ss).getLevel(); + doReturn(ss).when(mPhones[phoneId]).getSignalStrength(); + + Message msg = mAutoDataSwitchControllerUT.obtainMessage(EVENT_SIGNAL_STRENGTH_CHANGED); + msg.obj = new AsyncResult(phoneId, null, null); + mAutoDataSwitchControllerUT.sendMessage(msg); + processAllMessages(); + } + private void displayInfoChanged(int phoneId, TelephonyDisplayInfo telephonyDisplayInfo) { + doReturn(telephonyDisplayInfo).when(mDisplayInfoController).getTelephonyDisplayInfo(); + + Message msg = mAutoDataSwitchControllerUT.obtainMessage(EVENT_DISPLAY_INFO_CHANGED); + msg.obj = new AsyncResult(phoneId, null, null); + mAutoDataSwitchControllerUT.sendMessage(msg); + processAllMessages(); + } private void serviceStateChanged(int phoneId, @NetworkRegistrationInfo.RegistrationState int dataRegState) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java index 4b5189a0a9..c8ab0635bd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java @@ -16,9 +16,12 @@ package com.android.internal.telephony.data; +import static org.junit.Assert.assertNotEquals; + import android.net.InetAddresses; import android.net.LinkAddress; import android.os.Parcel; +import android.telephony.PreciseDataConnectionState; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.EpsQos; @@ -71,6 +74,8 @@ public class DataCallResponseTest extends AndroidTestCase { .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors( Arrays.asList(new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID))) + .setNetworkValidationStatus( + PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED) .build(); Parcel p = Parcel.obtain(); @@ -100,6 +105,8 @@ public class DataCallResponseTest extends AndroidTestCase { .setMtuV6(1400) .setTrafficDescriptors( Arrays.asList(new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID))) + .setNetworkValidationStatus( + PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS) .build(); DataCallResponse response1 = new DataCallResponse.Builder() @@ -119,6 +126,8 @@ public class DataCallResponseTest extends AndroidTestCase { .setMtuV6(1400) .setTrafficDescriptors( Arrays.asList(new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID))) + .setNetworkValidationStatus( + PreciseDataConnectionState.NETWORK_VALIDATION_IN_PROGRESS) .build(); assertEquals(response, response); @@ -145,11 +154,14 @@ public class DataCallResponseTest extends AndroidTestCase { .setTrafficDescriptors(Arrays.asList( new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID), new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2))) + .setNetworkValidationStatus(PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS) .build(); assertNotSame(response1, response2); assertNotSame(response1, null); assertNotSame(response1, new String[1]); + assertNotEquals(response1.getNetworkValidationStatus(), + response2.getNetworkValidationStatus()); assertNotSame(response1.hashCode(), response2.hashCode()); DataCallResponse response3 = new DataCallResponse.Builder() @@ -172,9 +184,12 @@ public class DataCallResponseTest extends AndroidTestCase { .setTrafficDescriptors(Arrays.asList( new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2), new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID))) + .setNetworkValidationStatus(PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS) .build(); assertEquals(response2, response3); + assertEquals(response2.getNetworkValidationStatus(), + response3.getNetworkValidationStatus()); assertEquals(response2.hashCode(), response3.hashCode()); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java index d4a0804b57..005b31209f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java @@ -18,18 +18,17 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import android.net.NetworkCapabilities; import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SignalStrength; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -51,8 +50,7 @@ public class DataConfigManagerTest extends TelephonyTest { logd("DataConfigManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); mBundle = mContextFixture.getCarrierConfigBundle(); - when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); - mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper()); + mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper(), mFeatureFlags); logd("DataConfigManagerTest -Setup!"); } @@ -130,19 +128,39 @@ public class DataConfigManagerTest extends TelephonyTest { TelephonyManager.NETWORK_TYPE_LTE, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, false/*isRoaming*/), signalStrength)).isEqualTo(10227); - // Verify if entry contains any invalid negative scores, should yield -1. + // Verify if entry contains any invalid negative scores, should yield 0. doReturn(SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN).when(signalStrength).getLevel(); assertThat(mDataConfigManagerUT.getAutoDataSwitchScore(new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false/*isRoaming*/), signalStrength)) - .isEqualTo(-1/*INVALID_AUTO_DATA_SWITCH_SCORE*/); + .isEqualTo(0/*OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE*/); // Verify non-existent entry should yield -1 doReturn(SignalStrength.SIGNAL_STRENGTH_POOR).when(signalStrength).getLevel(); assertThat(mDataConfigManagerUT.getAutoDataSwitchScore(new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_EDGE, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false/*isRoaming*/), signalStrength)) - .isEqualTo(-1/*INVALID_AUTO_DATA_SWITCH_SCORE*/); + .isEqualTo(0/*OUT_OF_SERVICE_AUTO_DATA_SWITCH_SCORE*/); + } + + @Test + public void testMeteredNetworkCapabilities() { + doReturn(true).when(mFeatureFlags).meteredEmbbUrlcc(); + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] {ApnSetting.TYPE_MMS_STRING, ApnSetting.TYPE_DEFAULT_STRING}); + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[] {ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_MCX_STRING}); + mDataConfigManagerUT.sendEmptyMessage(1/*EVENT_CARRIER_CONFIG_CHANGED*/); + processAllMessages(); + + assertThat(mDataConfigManagerUT.getMeteredNetworkCapabilities(false)).containsExactly( + NetworkCapabilities.NET_CAPABILITY_MMS, NetworkCapabilities.NET_CAPABILITY_INTERNET, + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH, + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY); + assertThat(mDataConfigManagerUT.getMeteredNetworkCapabilities(true)).containsExactly( + NetworkCapabilities.NET_CAPABILITY_SUPL, NetworkCapabilities.NET_CAPABILITY_MCX, + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH, + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataEvaluationTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataEvaluationTest.java index 63f3e4f5ac..6d4c0c14a4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataEvaluationTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataEvaluationTest.java @@ -16,10 +16,10 @@ package com.android.internal.telephony.data; -import com.android.internal.telephony.TelephonyTest; - import static com.google.common.truth.Truth.assertThat; +import com.android.internal.telephony.TelephonyTest; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -59,4 +59,32 @@ public class DataEvaluationTest extends TelephonyTest { DataEvaluation.DataDisallowedReason.DATA_DISABLED); assertThat(mDataEvaluationUT.getDataDisallowedReasons().size()).isEqualTo(1); } + + + @Test + public void testIsSubsetOf() { + mDataEvaluationUT = new DataEvaluation(DataEvaluation.DataEvaluationReason.DATA_RETRY); + assertThat(mDataEvaluationUT.isSubsetOf( + DataEvaluation.DataDisallowedReason.ROAMING_DISABLED)).isTrue(); + mDataEvaluationUT.addDataDisallowedReason( + DataEvaluation.DataDisallowedReason.DATA_DISABLED); + assertThat(mDataEvaluationUT.isSubsetOf( + DataEvaluation.DataDisallowedReason.DATA_DISABLED)).isTrue(); + assertThat(mDataEvaluationUT.isSubsetOf( + DataEvaluation.DataDisallowedReason.ROAMING_DISABLED)).isFalse(); + } + + @Test + public void testContainsOnly() { + mDataEvaluationUT = new DataEvaluation(DataEvaluation.DataEvaluationReason.DATA_RETRY); + assertThat(mDataEvaluationUT.containsOnly( + DataEvaluation.DataDisallowedReason.ROAMING_DISABLED)).isFalse(); + mDataEvaluationUT.addDataDisallowedReason( + DataEvaluation.DataDisallowedReason.DATA_DISABLED); + assertThat(mDataEvaluationUT.containsOnly( + DataEvaluation.DataDisallowedReason.DATA_DISABLED)).isTrue(); + assertThat(mDataEvaluationUT.containsOnly( + DataEvaluation.DataDisallowedReason.ROAMING_DISABLED)).isFalse(); + } + } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java index d96bac49b8..a2c972488f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -115,6 +115,7 @@ import com.android.internal.telephony.data.DataEvaluation.DataDisallowedReason; import com.android.internal.telephony.data.DataNetworkController.HandoverRule; import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.ims.ImsResolver; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -149,6 +150,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Events private static final int EVENT_SIM_STATE_CHANGED = 9; private static final int EVENT_REEVALUATE_EXISTING_DATA_NETWORKS = 16; + private static final int EVENT_SERVICE_STATE_CHANGED = 17; private static final int EVENT_VOICE_CALL_ENDED = 18; private static final int EVENT_SUBSCRIPTION_OVERRIDE = 23; @@ -158,7 +160,7 @@ public class DataNetworkControllerTest extends TelephonyTest { private DataNetworkControllerCallback mMockedDataNetworkControllerCallback; private DataRetryManagerCallback mMockedDataRetryManagerCallback; private ImsResolver mMockedImsResolver; - + private DataStallRecoveryManager mMockedDataStallRecoveryManager; private ImsManager mMockedImsManager; private ImsMmTelManager mMockedImsMmTelManager; private ImsRcsManager mMockedImsRcsManager; @@ -179,6 +181,10 @@ public class DataNetworkControllerTest extends TelephonyTest { private AccessNetworksManagerCallback mAccessNetworksManagerCallback; private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; + private boolean mIsNonTerrestrialNetwork = false; + private ArrayList<Integer> mCarrierSupportedSatelliteServices = new ArrayList<>(); + private FeatureFlags mFeatureFlags; + private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setId(2163) @@ -204,6 +210,8 @@ public class DataNetworkControllerTest extends TelephonyTest { .setMaxConns(321) .setWaitTime(456) .setMaxConnsTime(789) + .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE + | ApnSetting.INFRASTRUCTURE_CELLULAR) .build()) .setPreferred(false) .build(); @@ -385,6 +393,69 @@ public class DataNetworkControllerTest extends TelephonyTest { "PRIORITIZE_LATENCY", 1).getBytes())) .build(); + private final DataProfile mMmsOnWlanDataProfile = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("mms_wlan") + .setApnName("mms_wlan") + .setApnTypeBitmask(ApnSetting.TYPE_MMS) + .setCarrierEnabled(true) + .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN) + .build()) + .setPreferred(false) + .build(); + + private final DataProfile mNtnDataProfile = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("ntn") + .setApnName("ntn") + .setApnTypeBitmask(ApnSetting.TYPE_RCS) + .setCarrierEnabled(true) + .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE) + .build()) + .setPreferred(false) + .build(); + + private final DataProfile mEsimBootstrapDataProfile = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("ESIM BOOTSTRAP") + .setApnName("ESIM BOOTSTRAP") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT) + .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) + .setCarrierEnabled(true) + .setEsimBootstrapProvisioning(true) + .build()) + .setPreferred(false) + .build(); + + private final DataProfile mEsimBootstrapImsProfile = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("IMS BOOTSTRAP") + .setApnName("IMS BOOTSTRAP") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) + .setCarrierEnabled(true) + .setEsimBootstrapProvisioning(true) + .build()) + .setPreferred(false) + .build(); + + private final DataProfile mEsimBootstrapRcsInfraStructureProfile = + new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("INFRASTRUCTURE BOOTSTRAP") + .setApnName("INFRASTRUCTURE BOOTSTRAP") + .setApnTypeBitmask(ApnSetting.TYPE_RCS) + .setNetworkTypeBitmask((int) TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) + .setCarrierEnabled(true) + .setInfrastructureBitmask(2) + .setEsimBootstrapProvisioning(true) + .build()) + .setPreferred(false) + .build(); + /** Data call response map. The first key is the transport type, the second key is the cid. */ private final Map<Integer, Map<Integer, DataCallResponse>> mDataCallResponses = new HashMap<>(); @@ -583,7 +654,7 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(ss).when(mSST).getServiceState(); doReturn(ss).when(mPhone).getServiceState(); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); } @@ -609,6 +680,8 @@ public class DataNetworkControllerTest extends TelephonyTest { .setRegistrationState(dataRegState) .setDomain(NetworkRegistrationInfo.DOMAIN_PS) .setDataSpecificInfo(dsri) + .setIsNonTerrestrialNetwork(mIsNonTerrestrialNetwork) + .setAvailableServices(mCarrierSupportedSatelliteServices) .build()); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() @@ -616,6 +689,8 @@ public class DataNetworkControllerTest extends TelephonyTest { .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) .setRegistrationState(iwlanRegState) .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setIsNonTerrestrialNetwork(mIsNonTerrestrialNetwork) + .setAvailableServices(mCarrierSupportedSatelliteServices) .build()); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() @@ -726,6 +801,12 @@ public class DataNetworkControllerTest extends TelephonyTest { .KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY, new int[]{NetworkCapabilities.NET_CAPABILITY_IMS}); + mCarrierConfig.putLongArray(CarrierConfigManager.KEY_DATA_STALL_RECOVERY_TIMERS_LONG_ARRAY, + new long[] {100, 100, 100, 100}); + mCarrierConfig.putBooleanArray( + CarrierConfigManager.KEY_DATA_STALL_RECOVERY_SHOULD_SKIP_BOOL_ARRAY, + new boolean[] {false, false, true, false, false}); + mContextFixture.putResource(com.android.internal.R.string.config_bandwidthEstimateSource, "bandwidth_estimator"); @@ -747,9 +828,11 @@ public class DataNetworkControllerTest extends TelephonyTest { mMockedImsMmTelManager = Mockito.mock(ImsMmTelManager.class); mMockedImsRcsManager = Mockito.mock(ImsRcsManager.class); mMockedImsResolver = Mockito.mock(ImsResolver.class); + mMockedDataStallRecoveryManager = Mockito.mock(DataStallRecoveryManager.class); mMockedDataNetworkControllerCallback = Mockito.mock(DataNetworkControllerCallback.class); mMockedDataRetryManagerCallback = Mockito.mock(DataRetryManagerCallback.class); mMockSubInfo = Mockito.mock(SubscriptionInfo.class); + mFeatureFlags = Mockito.mock(FeatureFlags.class); when(mTelephonyComponentFactory.makeDataSettingsManager(any(Phone.class), any(DataNetworkController.class), any(Looper.class), any(DataSettingsManager.DataSettingsManagerCallback.class))).thenCallRealMethod(); @@ -831,7 +914,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // to test, in this case, DataNetworkController. But since there are too many interactions // between DataNetworkController and its sub-modules, we intend to make those modules "real" // as well, except some modules below we replaced with mocks. - mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper()); + mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper(), + mFeatureFlags); // First two come from DataServiceManager and the third comes from DataConfigManager which // is what we want to capture and assign to mCarrierConfigChangeListener verify(mCarrierConfigManager, times(3)).registerCarrierConfigChangeListener(any(), @@ -858,6 +942,8 @@ public class DataNetworkControllerTest extends TelephonyTest { replaceInstance(DataNetworkController.class, "mAccessNetworksManager", mDataNetworkControllerUT, mAccessNetworksManager); replaceInstance(ImsResolver.class, "sInstance", null, mMockedImsResolver); + replaceInstance(DataNetworkController.class, "mDataStallRecoveryManager", + mDataNetworkControllerUT, mMockedDataStallRecoveryManager); ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor = ArgumentCaptor.forClass(AccessNetworksManagerCallback.class); @@ -873,7 +959,9 @@ public class DataNetworkControllerTest extends TelephonyTest { List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile, mGeneralPurposeDataProfileAlternative, mImsCellularDataProfile, mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile, - mTetheringDataProfile); + mTetheringDataProfile, mMmsOnWlanDataProfile, mLowLatencyDataProfile, + mNtnDataProfile, mEsimBootstrapDataProfile, + mEsimBootstrapImsProfile, mEsimBootstrapRcsInfraStructureProfile); doAnswer(invocation -> { DataProfile dp = (DataProfile) invocation.getArguments()[0]; @@ -904,23 +992,35 @@ public class DataNetworkControllerTest extends TelephonyTest { TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) invocation.getArguments()[0]; int networkType = (int) invocation.getArguments()[1]; - boolean ignorePermanentFailure = (boolean) invocation.getArguments()[2]; + boolean isNtn = (boolean) invocation.getArguments()[2]; + boolean isEsimBootstrapProvisioning = (boolean) invocation.getArguments()[3]; + boolean ignorePermanentFailure = (boolean) invocation.getArguments()[4]; for (DataProfile dataProfile : profiles) { - if (dataProfile.canSatisfy(networkRequest.getCapabilities()) - && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0 - || (dataProfile.getApnSetting().getNetworkTypeBitmask() + ApnSetting apnSetting = dataProfile.getApnSetting(); + if (apnSetting != null + && dataProfile.canSatisfy(networkRequest.getCapabilities()) + && (apnSetting.getNetworkTypeBitmask() == 0 + || (apnSetting.getNetworkTypeBitmask() & ServiceState.getBitmaskForTech(networkType)) != 0) - && (ignorePermanentFailure || (dataProfile.getApnSetting() != null - && !dataProfile.getApnSetting().getPermanentFailed()))) { + && (isEsimBootstrapProvisioning + == apnSetting.isEsimBootstrapProvisioning()) + && ((isNtn && apnSetting.isForInfrastructure( + ApnSetting.INFRASTRUCTURE_SATELLITE)) + || (!isNtn && apnSetting.isForInfrastructure( + ApnSetting.INFRASTRUCTURE_CELLULAR))) + && (ignorePermanentFailure || !apnSetting.getPermanentFailed())) { return dataProfile; } } logd("Cannot find data profile to satisfy " + networkRequest + ", network type=" - + TelephonyManager.getNetworkTypeName(networkType)); + + TelephonyManager.getNetworkTypeName(networkType) + ", ignorePermanentFailure=" + + ignorePermanentFailure + ", isNtn=" + isNtn + "," + + "isEsimBootstrapProvisioning=" + isEsimBootstrapProvisioning); return null; }).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); + any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean(), + anyBoolean()); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(anyInt()); @@ -1090,7 +1190,7 @@ public class DataNetworkControllerTest extends TelephonyTest { } private void verifyInternetConnected() throws Exception { - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); } @@ -1128,6 +1228,18 @@ public class DataNetworkControllerTest extends TelephonyTest { + dataNetworkList); } + private void verifyConnectedNetworkHasNoDataProfile(@NonNull DataProfile dataProfile) + throws Exception { + List<DataNetwork> dataNetworkList = getDataNetworks(); + for (DataNetwork dataNetwork : getDataNetworks()) { + if (dataNetwork.isConnected() && dataNetwork.getDataProfile().equals(dataProfile)) { + fail("network with " + dataProfile + " is connected. dataNetworkList=" + + dataNetworkList); + } + } + return; + } + private void verifyAllDataDisconnected() throws Exception { List<DataNetwork> dataNetworkList = getDataNetworks(); assertWithMessage("All data should be disconnected but it's not. " + dataNetworkList) @@ -1150,7 +1262,7 @@ public class DataNetworkControllerTest extends TelephonyTest { InetAddresses.parseNumericAddress(IPV4_ADDRESS), InetAddresses.parseNumericAddress(IPV6_ADDRESS)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); } @Test @@ -1168,7 +1280,7 @@ public class DataNetworkControllerTest extends TelephonyTest { InetAddresses.parseNumericAddress(IPV4_ADDRESS), InetAddresses.parseNumericAddress(IPV6_ADDRESS)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); // database updated/reloaded, causing data profile id change List<DataProfile> profiles = List.of(mDuplicatedGeneralPurposeDataProfile); @@ -1202,10 +1314,11 @@ public class DataNetworkControllerTest extends TelephonyTest { + TelephonyManager.getNetworkTypeName(networkType)); return null; }).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); + any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean(), + anyBoolean()); // verify the network still connects - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); // A NOT_VCN_MANAGED request cannot be satisfied by the existing network, but will adopt the // same data profile @@ -1216,7 +1329,7 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); // verify the network still connects - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); // verify we don't try to setup a separate network for the not_vcn_managed request dataNetworkList = getDataNetworks(); assertThat(dataNetworkList).hasSize(1); @@ -1247,7 +1360,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); doReturn(mEnterpriseDataProfile).when(mDataProfileManager) .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); NetworkCapabilities netCaps = new NetworkCapabilities(); netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); @@ -1279,7 +1392,7 @@ public class DataNetworkControllerTest extends TelephonyTest { mDataNetworkControllerUT.addNetworkRequest(request); processAllMessages(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(true)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any()); int countOfCallbacks = dataNetworkControllerCallbacks.size(); @@ -1302,7 +1415,8 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged( + eq(Collections.emptySet())); verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( eq(DataCallResponse.LINK_STATUS_INACTIVE)); } @@ -1461,12 +1575,13 @@ public class DataNetworkControllerTest extends TelephonyTest { // Now RAT changes from UMTS to GSM doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged( + eq(Collections.emptySet())); verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( eq(DataCallResponse.LINK_STATUS_INACTIVE)); @@ -1474,14 +1589,14 @@ public class DataNetworkControllerTest extends TelephonyTest { // Now RAT changes from GSM to UMTS doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager) .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); // Now RAT changes from UMTS to LTE serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); @@ -1555,6 +1670,74 @@ public class DataNetworkControllerTest extends TelephonyTest { } @Test + public void testNonTerrestrialNetworkChangedWithoutDataSupport() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mIsNonTerrestrialNetwork = true; + // Data is not supported while using satellite + mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Data with internet capability should not be allowed + // when the device is using non-terrestrial network + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + mIsNonTerrestrialNetwork = false; + mCarrierSupportedSatelliteServices.clear(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + + // Verify data is restored. + verifyInternetConnected(); + } + + @Test + public void testNonTerrestrialNetworkWithDataSupport() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mIsNonTerrestrialNetwork = true; + // Data is supported while using satellite + mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_DATA); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Verify data is connected. + verifyInternetConnected(); + + mIsNonTerrestrialNetwork = false; + mCarrierSupportedSatelliteServices.clear(); + } + + @Test + public void testNonTerrestrialNetworkWithFlagDisabled() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + + mIsNonTerrestrialNetwork = true; + // Data is not supported while using satellite + mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // As feature is disabled, data is connected. + verifyInternetConnected(); + + mIsNonTerrestrialNetwork = false; + mCarrierSupportedSatelliteServices.clear(); + } + + + @Test public void testRoamingDataChanged() throws Exception { doReturn(true).when(mServiceState).getDataRoaming(); @@ -1578,7 +1761,6 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify data is restored. verifyInternetConnected(); - Mockito.clearInvocations(mMockedDataNetworkControllerCallback); // Roaming data disabled mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(false); @@ -1586,6 +1768,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify data is torn down. verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + Mockito.clearInvocations(mMockedDataNetworkControllerCallback); // Registration is back to HOME. serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, @@ -1744,9 +1927,13 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testIsDataEnabledOverriddenForApnDataDuringCall() throws Exception { - doReturn(1).when(mPhone).getSubId(); + // Assume phone2 is the default data phone + Phone phone2 = Mockito.mock(Phone.class); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); - // Data disabled + doReturn(1).when(mPhone).getSubId(); + + // Data disabled on nonDDS mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); @@ -1766,6 +1953,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // Phone ringing doReturn(PhoneConstants.State.RINGING).when(mPhone).getState(); + // Data is user enabled on DDS + doReturn(true).when(phone2).isUserDataEnabled(); mDataNetworkControllerUT.addNetworkRequest( createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); processAllMessages(); @@ -2352,8 +2541,7 @@ public class DataNetworkControllerTest extends TelephonyTest { new String[]{"source=EUTRAN, target=IWLAN, type=disallowed, capabilities=MMS|IMS", "source=IWLAN, target=EUTRAN, type=disallowed, capabilities=MMS"}); // Force data config manager to reload the carrier config. - mDataNetworkControllerUT.getDataConfigManager().obtainMessage( - 1/*EVENT_CARRIER_CONFIG_CHANGED*/).sendToTarget(); + carrierConfigChanged(); processAllMessages(); testSetupImsDataNetwork(); @@ -2394,6 +2582,36 @@ public class DataNetworkControllerTest extends TelephonyTest { } @Test + public void testHandoverDataNetworkNotAllowedByPolicyDelayDueToVoiceCall() throws Exception { + doReturn(true).when(mFeatureFlags).relaxHoTeardown(); + // Config delay IMS tear down enabled + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, + true); + mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, + new String[]{"source=EUTRAN, target=IWLAN, type=disallowed, capabilities=MMS|IMS"}); + carrierConfigChanged(); + + testSetupImsDataNetwork(); + + // Ringing an active call, should delay handover tear down + doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); + updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + // Verify network is still connected due to active voice call + verify(mMockedWwanDataServiceManager, never()).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + + // Verify tear down after call ends + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); + processAllFutureMessages(); + + verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + } + + @Test public void testHandoverDataNetworkNotAllowedByRoamingPolicy() throws Exception { mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{"source=EUTRAN|NGRAN|IWLAN, target=EUTRAN|NGRAN|IWLAN, roaming=true, " @@ -3139,7 +3357,7 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); verify(mMockedDataNetworkControllerCallback) - .onInternetDataNetworkConnected(any()); + .onConnectedInternetDataNetworksChanged(any()); List<DataNetwork> dataNetworks = getDataNetworks(); assertThat(dataNetworks).hasSize(1); assertThat(dataNetworks.get(0).getNetworkCapabilities().hasCapability( @@ -3373,7 +3591,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); doReturn(mEnterpriseDataProfile).when(mDataProfileManager) .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); NetworkCapabilities netCaps = new NetworkCapabilities(); netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); @@ -3417,8 +3635,12 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testNonVoPStoVoPSImsSetup() throws Exception { - // Even allow lingering when NoVops, should have no effect on NoVops -> Vops - mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); + doReturn(true).when(mFeatureFlags).allowMmtelInNonVops(); + mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(true); + // Config that allows non-vops bring up when Roaming + mCarrierConfig.putIntArray(CarrierConfigManager.Ims + .KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY, new int[] + {CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING}); carrierConfigChanged(); // VOPS not supported @@ -3438,6 +3660,30 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + // Verify bring up in Home is not allowed. + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + processAllMessages(); + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + + // Verify bring up in Roaming is allowed. + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, dsri); + processAllMessages(); + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + // Verify the roaming network survives network re-evaluation. + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) + .sendToTarget(); + processAllMessages(); + + // Service state changed to Home, non-vops area is no longer allowed + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + processAllMessages(); + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + // VoPS supported dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) @@ -4013,8 +4259,6 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testHandoverDataNetworkNonVops() throws Exception { - ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) .setEnDcAvailable(true) @@ -4022,36 +4266,13 @@ public class DataNetworkControllerTest extends TelephonyTest { LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) .build(); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setDataSpecificInfo(dsri) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); mDataNetworkControllerUT.addNetworkRequest( @@ -4080,8 +4301,6 @@ public class DataNetworkControllerTest extends TelephonyTest { mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); carrierConfigChanged(); - ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) .setEnDcAvailable(true) @@ -4089,36 +4308,13 @@ public class DataNetworkControllerTest extends TelephonyTest { LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) .build(); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setDataSpecificInfo(dsri) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); mDataNetworkControllerUT.addNetworkRequest( @@ -4144,8 +4340,6 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testNonMmtelImsHandoverDataNetworkNonVops() throws Exception { - ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) .setEnDcAvailable(true) @@ -4154,35 +4348,13 @@ public class DataNetworkControllerTest extends TelephonyTest { LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) .build(); - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setDataSpecificInfo(dsri) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); // Bring up the IMS network that does not require MMTEL @@ -4190,7 +4362,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); processAllMessages(); - // Even though the network request does not have MMTEL, but the network support it, so + // Even though the network request does not have MMTEL, the WLAN network support it, so // the network capabilities should still have MMTEL. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); @@ -4204,9 +4376,9 @@ public class DataNetworkControllerTest extends TelephonyTest { any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); - // The IMS network should still have IMS and MMTEL. + // The IMS network should still have IMS, but MMTEL is removed. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); - verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL); + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); } @Test @@ -4215,8 +4387,6 @@ public class DataNetworkControllerTest extends TelephonyTest { mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true); carrierConfigChanged(); - ServiceState ss = new ServiceState(); - // VoPS network DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) @@ -4226,35 +4396,13 @@ public class DataNetworkControllerTest extends TelephonyTest { LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) .build(); - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setDataSpecificInfo(dsri) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); // Bring up the IMS network that does require MMTEL @@ -4267,7 +4415,6 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); - ss = new ServiceState(); // Non VoPS network dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) @@ -4277,32 +4424,10 @@ public class DataNetworkControllerTest extends TelephonyTest { LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) .build(); - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setDataSpecificInfo(dsri) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); processAllMessages(); // The IMS network is alive due to KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL = true @@ -4386,7 +4511,8 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); - verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); + verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged( + eq(Collections.emptySet())); verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( eq(DataCallResponse.LINK_STATUS_INACTIVE)); } @@ -4505,7 +4631,7 @@ public class DataNetworkControllerTest extends TelephonyTest { NetworkRegistrationInfo.REGISTRATION_STATE_HOME, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); doReturn(ss).when(mSST).getServiceState(); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget(); mDataNetworkControllerUT.removeNetworkRequest(request); mDataNetworkControllerUT.addNetworkRequest(request); processAllMessages(); @@ -4527,7 +4653,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); doReturn(mEnterpriseDataProfile).when(mDataProfileManager) .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest( new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) @@ -4565,7 +4691,7 @@ public class DataNetworkControllerTest extends TelephonyTest { createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); doReturn(mLowLatencyDataProfile).when(mDataProfileManager) .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), - anyBoolean()); + anyBoolean(), anyBoolean(), anyBoolean()); processAllFutureMessages(); dataNetworkList = getDataNetworks(); @@ -4580,4 +4706,228 @@ public class DataNetworkControllerTest extends TelephonyTest { assertThat(dataNetworkList.get(1).getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)).isTrue(); } + + @Test + public void testAllowBringUpWithDifferentDataProfileForWlan() throws Exception { + // Mock MMS preferred on WLAN + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_MMS); + + // Setup a default cellular network that's capable of MMS + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS)); + processAllMessages(); + verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); + + // Mock the designated MMS profile when WLAN is preferred + doReturn(mMmsOnWlanDataProfile).when(mDataProfileManager).getDataProfileForNetworkRequest( + any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_IWLAN), + anyBoolean(), anyBoolean(), anyBoolean()); + setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, + createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE)); + + // Verify the designated MMS profile is used to satisfy MMS request + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); + processAllMessages(); + verifyConnectedNetworkHasDataProfile(mMmsOnWlanDataProfile); + } + + @Test + public void testNonTerrestrialNetwork() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mIsNonTerrestrialNetwork = true; + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS)); + processAllMessages(); + verifyConnectedNetworkHasDataProfile(mNtnDataProfile); + } + + @Test + public void testIsEsimBootStrapProvisioningActivatedWithFlagEnabledAndProvisioningClass() { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue(); + } + + @Test + public void testIsEsimBootStrapProvisioningActivatedWithFlagEnabledAndNoProvisioningClass() { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse(); + } + + @Test + public void testIsEsimBootStrapProvisioningActivatedWithFlagDisabledAndNoProvisioningClass() { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(false); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse(); + } + + @Test + public void testIsEsimBootStrapProvisioningActivatedWithFlagDisabledAndProvisioningClass() { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(false); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isFalse(); + } + + @Test + public void testNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + verifyConnectedNetworkHasDataProfile(mEsimBootstrapDataProfile); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL)); + setSuccessfulSetupDataResponse(mMockedDataServiceManagers + .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); + processAllMessages(); + verifyConnectedNetworkHasDataProfile(mEsimBootstrapImsProfile); + + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS)); + processAllMessages(); + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_RCS); + } + + @Test + public void testNetworkOnNonProvisioningProfileClass_WithFlagEnabled() throws Exception { + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_UNSET).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapDataProfile); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL)); + setSuccessfulSetupDataResponse(mMockedDataServiceManagers + .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); + processAllMessages(); + verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapImsProfile); + } + + @Test + public void testNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + mIsNonTerrestrialNetwork = true; + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS)); + processAllMessages(); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue(); + verifyConnectedNetworkHasNoDataProfile(mNtnDataProfile); + verifyConnectedNetworkHasDataProfile(mEsimBootstrapRcsInfraStructureProfile); + } + + @Test + public void testNonNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true); + doReturn(new SubscriptionInfoInternal.Builder().setId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS)); + processAllMessages(); + + assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue(); + verifyConnectedNetworkHasNoDataProfile(mNtnDataProfile); + verifyConnectedNetworkHasNoDataProfile(mEsimBootstrapRcsInfraStructureProfile); + } + + @Test + public void testRequestNetworkValidationWithConnectedNetwork() throws Exception { + // IMS preferred on IWLAN. + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getPreferredTransportByNetworkCapability( + eq(NetworkCapabilities.NET_CAPABILITY_IMS)); + + // Request IMS + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL)); + setSuccessfulSetupDataResponse(mMockedDataServiceManagers + .get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN), 3); + processAllMessages(); + + // Make sure IMS on IWLAN. + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS); + DataNetwork dataNetwork = getDataNetworks().get(0); + assertThat(dataNetwork.getTransport()).isEqualTo( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + mDataNetworkControllerUT.requestNetworkValidation(NetworkCapabilities.NET_CAPABILITY_IMS, + mIntegerConsumer); + processAllMessages(); + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isFalse(); + } + + @Test + public void testRequestNetworkValidationWithNoConnectedNetwork() + throws Exception { + // IMS preferred on IWLAN. + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getPreferredTransportByNetworkCapability( + eq(NetworkCapabilities.NET_CAPABILITY_IMS)); + + // IMS On Wlan not connected + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + + //Connected List is Empty + mDataNetworkControllerUT.requestNetworkValidation(NetworkCapabilities.NET_CAPABILITY_IMS, + mIntegerConsumer); + processAllMessages(); + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isTrue(); + assertThat(mIntegerConsumerResult).isEqualTo(DataServiceCallback.RESULT_ERROR_INVALID_ARG); + } + + @Test + public void testRequestNetworkValidationWithInvalidArg() { + mDataNetworkControllerUT.requestNetworkValidation( + NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY, + mIntegerConsumer); + processAllMessages(); + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isTrue(); + assertThat(mIntegerConsumerResult).isEqualTo(DataServiceCallback.RESULT_ERROR_INVALID_ARG); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java index 41a714ca70..5dd83bf77b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.net.ConnectivityManager; import android.net.InetAddresses; @@ -39,6 +40,7 @@ import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; import android.net.vcn.VcnNetworkPolicyResult; import android.os.AsyncResult; @@ -63,7 +65,9 @@ import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.DataService; import android.telephony.data.DataServiceCallback; +import android.telephony.data.EpsQos; import android.telephony.data.NetworkSliceInfo; +import android.telephony.data.Qos; import android.telephony.data.TrafficDescriptor; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -76,6 +80,7 @@ import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCa import com.android.internal.telephony.data.DataEvaluation.DataAllowedReason; import com.android.internal.telephony.data.DataNetwork.DataNetworkCallback; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; +import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; import com.android.internal.telephony.metrics.DataCallSessionStats; @@ -92,7 +97,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; - @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class DataNetworkTest extends TelephonyTest { @@ -204,6 +208,11 @@ public class DataNetworkTest extends TelephonyTest { .setTrafficDescriptor(new TrafficDescriptor(null, null)) .build(); + private final Qos mDefaultQos = new EpsQos( + new Qos.QosBandwidth(1000, 1), + new Qos.QosBandwidth(1000, 0), + 9 /* QCI */); + // Mocked classes private DataNetworkCallback mDataNetworkCallback; private DataCallSessionStats mDataCallSessionStats; @@ -216,16 +225,22 @@ public class DataNetworkTest extends TelephonyTest { .build(); private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid) { - setSuccessfulSetupDataResponse(dsm, cid, Collections.emptyList()); + setSuccessfulSetupDataResponse(dsm, cid, Collections.emptyList(), null); } private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid, List<TrafficDescriptor> tds) { + setSuccessfulSetupDataResponse(dsm, cid, tds, null); + } + + private void setSuccessfulSetupDataResponse(DataServiceManager dsm, int cid, + List<TrafficDescriptor> tds, Qos defaultQos) { doAnswer(invocation -> { final Message msg = (Message) invocation.getArguments()[10]; DataCallResponse response = createDataCallResponse( - cid, DataCallResponse.LINK_STATUS_ACTIVE, tds); + cid, DataCallResponse.LINK_STATUS_ACTIVE, tds, defaultQos, + PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); @@ -236,7 +251,7 @@ public class DataNetworkTest extends TelephonyTest { } private DataCallResponse createDataCallResponse(int cid, int linkStatus, - List<TrafficDescriptor> tds) { + List<TrafficDescriptor> tds, Qos defaultQos, int validationStatus) { return new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) @@ -260,6 +275,8 @@ public class DataNetworkTest extends TelephonyTest { .setPduSessionId(1) .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(tds) + .setDefaultQos(defaultQos) + .setNetworkValidationStatus(validationStatus) .build(); } @@ -410,10 +427,11 @@ public class DataNetworkTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); - setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); + setSuccessfulSetupDataResponse( + mMockedWwanDataServiceManager, 123, Collections.emptyList(), mDefaultQos); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -470,6 +488,7 @@ public class DataNetworkTest extends TelephonyTest { assertThat(pdcsList.get(0).getTransportType()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); assertThat(pdcsList.get(0).getLinkProperties()).isEqualTo(new LinkProperties()); + assertThat(pdcsList.get(0).getDefaultQos()).isEqualTo(null); assertThat(pdcsList.get(1).getApnSetting()).isEqualTo(mInternetApnSetting); assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED); @@ -477,6 +496,7 @@ public class DataNetworkTest extends TelephonyTest { assertThat(pdcsList.get(1).getNetworkType()).isEqualTo(TelephonyManager.NETWORK_TYPE_LTE); assertThat(pdcsList.get(1).getTransportType()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + assertThat(pdcsList.get(1).getDefaultQos()).isEqualTo(mDefaultQos); assertThat(pdcsList.get(1).getLinkProperties().getAddresses().get(0)) .isEqualTo(InetAddresses.parseNumericAddress(IPV4_ADDRESS)); assertThat(pdcsList.get(1).getLinkProperties().getAddresses().get(1)) @@ -519,8 +539,8 @@ public class DataNetworkTest extends TelephonyTest { setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -615,8 +635,8 @@ public class DataNetworkTest extends TelephonyTest { .build(), mPhone)); setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); processAllMessages(); @@ -634,20 +654,7 @@ public class DataNetworkTest extends TelephonyTest { @Test public void testCreateImsDataNetwork() throws Exception { - NetworkRequestList networkRequestList = new NetworkRequestList(); - networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) - .build(), mPhone)); - - setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); - - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mImsDataProfile, networkRequestList, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - DataAllowedReason.NORMAL, mDataNetworkCallback); - replaceInstance(DataNetwork.class, "mDataCallSessionStats", - mDataNetworkUT, mDataCallSessionStats); - processAllMessages(); + createImsDataNetwork(true/*isMmtel*/); ArgumentCaptor<LinkProperties> linkPropertiesCaptor = ArgumentCaptor.forClass(LinkProperties.class); @@ -668,7 +675,7 @@ public class DataNetworkTest extends TelephonyTest { eq(DataCallResponse.PDU_SESSION_ID_NOT_SET), nullable(NetworkSliceInfo.class), any(TrafficDescriptor.class), eq(true), any(Message.class)); assertThat(mDataNetworkUT.getId()).isEqualTo(123); - assertThat(networkRequestList.get(0).getState()) + assertThat(mDataNetworkUT.getAttachedNetworkRequestList().get(0).getState()) .isEqualTo(TelephonyNetworkRequest.REQUEST_STATE_SATISFIED); LinkProperties lp = mDataNetworkUT.getLinkProperties(); assertThat(lp.getAddresses()).containsExactly( @@ -724,8 +731,8 @@ public class DataNetworkTest extends TelephonyTest { ); setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mEnterpriseDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mEnterpriseDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -758,8 +765,8 @@ public class DataNetworkTest extends TelephonyTest { ); setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mUrlccDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mUrlccDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -791,8 +798,8 @@ public class DataNetworkTest extends TelephonyTest { ); setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mEmbbDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mEmbbDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -825,8 +832,8 @@ public class DataNetworkTest extends TelephonyTest { setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mCbsDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mCbsDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -857,8 +864,8 @@ public class DataNetworkTest extends TelephonyTest { .getBytes()) ); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mCbsDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mCbsDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -939,9 +946,10 @@ public class DataNetworkTest extends TelephonyTest { setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mImsDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WLAN, - DataAllowedReason.NORMAL, mDataNetworkCallback); + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mImsDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, DataAllowedReason.NORMAL, + mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", mDataNetworkUT, mDataCallSessionStats); processAllMessages(); @@ -1029,6 +1037,9 @@ public class DataNetworkTest extends TelephonyTest { setupDataNetwork(); setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456); + TelephonyNetworkAgent mockNetworkAgent = Mockito.mock(TelephonyNetworkAgent.class); + replaceInstance(DataNetwork.class, "mNetworkAgent", + mDataNetworkUT, mockNetworkAgent); // Now handover to IWLAN mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null); processAllMessages(); @@ -1053,6 +1064,18 @@ public class DataNetworkTest extends TelephonyTest { .isEqualTo(TelephonyManager.DATA_HANDOVER_IN_PROGRESS); assertThat(pdcsList.get(3).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED); + ArgumentCaptor<NetworkScore> networkScoreCaptor = + ArgumentCaptor.forClass(NetworkScore.class); + verify(mockNetworkAgent, times(2)) + .sendNetworkScore(networkScoreCaptor.capture()); + List<NetworkScore> networkScoreList = networkScoreCaptor.getAllValues(); + + assertThat(networkScoreList).hasSize(2); + assertThat(networkScoreList.get(0).getKeepConnectedReason()) + .isEqualTo(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER); + assertThat(networkScoreList.get(1).getKeepConnectedReason()) + .isEqualTo(NetworkScore.KEEP_CONNECTED_NONE); + // Now handover back to cellular Mockito.clearInvocations(mDataNetworkCallback); Mockito.clearInvocations(mLinkBandwidthEstimator); @@ -1072,6 +1095,9 @@ public class DataNetworkTest extends TelephonyTest { public void testHandoverFailed() throws Exception { setupDataNetwork(); + TelephonyNetworkAgent mockNetworkAgent = Mockito.mock(TelephonyNetworkAgent.class); + replaceInstance(DataNetwork.class, "mNetworkAgent", + mDataNetworkUT, mockNetworkAgent); setFailedSetupDataResponse(mMockedWlanDataServiceManager, DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE); // Now attempt to handover to IWLAN but fail it. @@ -1101,6 +1127,18 @@ public class DataNetworkTest extends TelephonyTest { assertThat(pdcsList.get(3).getLastCauseCode()) .isEqualTo(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE); + ArgumentCaptor<NetworkScore> networkScoreCaptor = + ArgumentCaptor.forClass(NetworkScore.class); + verify(mockNetworkAgent, times(2)) + .sendNetworkScore(networkScoreCaptor.capture()); + List<NetworkScore> networkScoreList = networkScoreCaptor.getAllValues(); + + assertThat(networkScoreList).hasSize(2); + assertThat(networkScoreList.get(0).getKeepConnectedReason()) + .isEqualTo(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER); + assertThat(networkScoreList.get(1).getKeepConnectedReason()) + .isEqualTo(NetworkScore.KEEP_CONNECTED_NONE); + // Test source PDN lost during the HO, expect tear down after HO setFailedSetupDataResponse(mMockedWlanDataServiceManager, DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE); @@ -1131,8 +1169,8 @@ public class DataNetworkTest extends TelephonyTest { setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -1218,6 +1256,88 @@ public class DataNetworkTest extends TelephonyTest { } @Test + public void testRestrictedNetworkDataEnabled() throws Exception { + NetworkRequestList networkRequestList = new NetworkRequestList(); + // Restricted network request + networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(), mPhone)); + + // Data disabled + doReturn(false).when(mDataSettingsManager).isDataEnabled(); + setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); + + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback); + replaceInstance(DataNetwork.class, "mDataCallSessionStats", + mDataNetworkUT, mDataCallSessionStats); + mDataNetworkUT.sendMessage(18/*EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED*/, + new AsyncResult(null, new int[]{ADMIN_UID1, ADMIN_UID2}, null)); + processAllMessages(); + + assertThat(mDataNetworkUT.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)).isFalse(); + + ArgumentCaptor<DataSettingsManagerCallback> dataSettingsManagerCallbackCaptor = + ArgumentCaptor.forClass(DataSettingsManagerCallback.class); + verify(mDataSettingsManager).registerCallback(dataSettingsManagerCallbackCaptor.capture()); + + // Data enabled + doReturn(true).when(mDataSettingsManager).isDataEnabled(); + dataSettingsManagerCallbackCaptor.getValue().onDataEnabledChanged(true, + TelephonyManager.DATA_ENABLED_REASON_USER, ""); + + // Network should become unrestricted. + assertThat(mDataNetworkUT.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)).isTrue(); + } + + @Test + public void testRestrictedNetworkDataRoamingEnabled() throws Exception { + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + + NetworkRequestList networkRequestList = new NetworkRequestList(); + // Restricted network request + networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(), mPhone)); + + // Data roaming disabled + doReturn(false).when(mDataSettingsManager).isDataRoamingEnabled(); + setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); + + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback); + replaceInstance(DataNetwork.class, "mDataCallSessionStats", + mDataNetworkUT, mDataCallSessionStats); + mDataNetworkUT.sendMessage(18/*EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED*/, + new AsyncResult(null, new int[]{ADMIN_UID1, ADMIN_UID2}, null)); + processAllMessages(); + + assertThat(mDataNetworkUT.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)).isFalse(); + + ArgumentCaptor<DataSettingsManagerCallback> dataSettingsManagerCallbackCaptor = + ArgumentCaptor.forClass(DataSettingsManagerCallback.class); + verify(mDataSettingsManager).registerCallback(dataSettingsManagerCallbackCaptor.capture()); + + // Data roaming enabled + doReturn(true).when(mDataSettingsManager).isDataRoamingEnabled(); + dataSettingsManagerCallbackCaptor.getValue().onDataRoamingEnabledChanged(true); + + // Network should become unrestricted. + assertThat(mDataNetworkUT.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)).isTrue(); + } + + @Test public void testVcnPolicyUpdated() throws Exception { setupDataNetwork(); @@ -1243,8 +1363,25 @@ public class DataNetworkTest extends TelephonyTest { @Test public void testVcnPolicyTeardownRequested() throws Exception { + // 1. Tear down in Connecting state + doAnswer(invocation -> { + NetworkCapabilities nc = invocation.getArgument(0); + + return new VcnNetworkPolicyResult( + true /* isTearDownRequested */, nc); + }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); setupDataNetwork(); + verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + + // 2. Tear down in Connected state + doAnswer(invocation -> { + NetworkCapabilities nc = invocation.getArgument(0); + return new VcnNetworkPolicyResult( + false /* isTearDownRequested */, nc); + }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); + setupDataNetwork(); doAnswer(invocation -> { NetworkCapabilities nc = invocation.getArgument(0); @@ -1281,7 +1418,7 @@ public class DataNetworkTest extends TelephonyTest { @Test public void testNetworkAgentConfig() throws Exception { - testCreateImsDataNetwork(); + createImsDataNetwork(false/*IsMmtel*/); ArgumentCaptor<NetworkAgentConfig> captor = ArgumentCaptor .forClass(NetworkAgentConfig.class); @@ -1307,8 +1444,8 @@ public class DataNetworkTest extends TelephonyTest { networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); NetworkCapabilities caps = mDataNetworkUT.getNetworkCapabilities(); @@ -1400,7 +1537,8 @@ public class DataNetworkTest extends TelephonyTest { } @Test - public void testMovingToNonVops() throws Exception { + public void testMovingToNonVopsRequestedMmtel() throws Exception { + createImsDataNetwork(true/*isMmtel*/); DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) .setNrAvailable(true) .setEnDcAvailable(true) @@ -1410,7 +1548,6 @@ public class DataNetworkTest extends TelephonyTest { .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); - testCreateImsDataNetwork(); assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue(); @@ -1431,6 +1568,37 @@ public class DataNetworkTest extends TelephonyTest { } @Test + public void testNonMmtelImsMovingToNonVops() throws Exception { + createImsDataNetwork(false/*isMmtel*/); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + + assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue(); + + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); + logd("Trigger non VoPS"); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); + // MMTEL should be removed to reflect the actual Vops status. + assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse(); + } + + @Test public void testCssIndicatorChanged() throws Exception { setupDataNetwork(); @@ -1661,8 +1829,8 @@ public class DataNetworkTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - mInternetDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mInternetDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -1804,8 +1972,8 @@ public class DataNetworkTest extends TelephonyTest { networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone)); - mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers, - m5gDataProfile, networkRequestList, + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, m5gDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL, mDataNetworkCallback); replaceInstance(DataNetwork.class, "mDataCallSessionStats", @@ -1831,7 +1999,8 @@ public class DataNetworkTest extends TelephonyTest { // data state updated DataCallResponse response = createDataCallResponse(123, - DataCallResponse.LINK_STATUS_DORMANT, Collections.emptyList()); + DataCallResponse.LINK_STATUS_DORMANT, Collections.emptyList(), null, + PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED); mDataNetworkUT.sendMessage(8 /*EVENT_DATA_STATE_CHANGED*/, new AsyncResult( AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)); processAllMessages(); @@ -1851,4 +2020,187 @@ public class DataNetworkTest extends TelephonyTest { verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT), eq(DataCallResponse.LINK_STATUS_INACTIVE)); } + + @Test + public void testHandleDataNetworkValidationRequestOnDataConnectedState() throws Exception { + setupIwlanDataNetwork(); + + // First Request + mDataNetworkUT.requestNetworkValidation(mIntegerConsumer); + processAllMessages(); + verify(mMockedWlanDataServiceManager).requestValidation(eq(123 /*cid*/), + any(Message.class)); + + // Duplicate Request + mDataNetworkUT.requestNetworkValidation(mIntegerConsumer); + processAllMessages(); + verify(mMockedWlanDataServiceManager).requestValidation(eq(123 /*cid*/), + any(Message.class)); + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isTrue(); + assertThat(mIntegerConsumerResult).isEqualTo(DataServiceCallback.RESULT_ERROR_BUSY); + } + + @Test + public void testHandleDataNetworkValidationRequestResultCode() throws Exception { + setupDataNetwork(); + mDataNetworkUT.requestNetworkValidation(mIntegerConsumer); + processAllMessages(); + + mDataNetworkUT.sendMessage(29 /*EVENT_DATA_NETWORK_VALIDATION_RESPONSE*/, + DataServiceCallback.RESULT_SUCCESS); + processAllMessages(); + + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isTrue(); + assertThat(mIntegerConsumerResult).isEqualTo(DataServiceCallback.RESULT_SUCCESS); + + //mNetworkValidationResultCodeCallback null case + mIntegerConsumerResult = DataServiceCallback.RESULT_ERROR_UNSUPPORTED; + mDataNetworkUT.sendMessage(29 /*EVENT_DATA_NETWORK_VALIDATION_RESPONSE*/, + DataServiceCallback.RESULT_SUCCESS); + processAllMessages(); + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isFalse(); + assertThat(mIntegerConsumerResult).isNotEqualTo(DataServiceCallback.RESULT_SUCCESS); + } + + @Test + public void testHandleDataNetworkValidationRequestNotConnectedState() throws Exception { + NetworkRequestList networkRequestList = new NetworkRequestList(); + NetworkRequest.Builder builder = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); + networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone)); + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mImsDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + DataAllowedReason.NORMAL, mDataNetworkCallback); + replaceInstance(DataNetwork.class, "mDataCallSessionStats", + mDataNetworkUT, mDataCallSessionStats); + processAllMessages(); + + // Data Not connected State + mDataNetworkUT.requestNetworkValidation(mIntegerConsumer); + processAllMessages(); + + assertThat(waitForIntegerConsumerResponse(1 /*numOfEvents*/)).isTrue(); + assertThat(mIntegerConsumerResult) + .isEqualTo(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + + @Test + public void testValidationStatusOnPreciseDataConnectionState_FlagEnabled() throws Exception { + when(mFeatureFlags.networkValidation()).thenReturn(true); + setupIwlanDataNetwork(); + + ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor = + ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(2)).notifyDataConnection(pdcsCaptor.capture()); + List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues(); + + assertThat(pdcsList.get(1).getApnSetting()).isEqualTo(mImsApnSetting); + assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED); + assertThat(pdcsList.get(1).getNetworkType()).isEqualTo(TelephonyManager.NETWORK_TYPE_IWLAN); + assertThat(pdcsList.get(1).getTransportType()) + .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + assertThat(pdcsList.get(1).getNetworkValidationStatus()) + .isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED); + + // Request Network Validation + mDataNetworkUT.requestNetworkValidation(mIntegerConsumer); + processAllMessages(); + verify(mMockedWlanDataServiceManager).requestValidation(eq(123 /*cid*/), + any(Message.class)); + + // data state updated with network validation status + DataCallResponse response = createDataCallResponse(123, + DataCallResponse.LINK_STATUS_ACTIVE, Collections.emptyList(), null, + PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS); + mDataNetworkUT.sendMessage(8 /*EVENT_DATA_STATE_CHANGED*/, new AsyncResult( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, List.of(response), null)); + processAllMessages(); + + // Verify updated validation status at precise data connection state + pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(3)).notifyDataConnection(pdcsCaptor.capture()); + + + // data state updated with same network validation status + response = createDataCallResponse(123, + DataCallResponse.LINK_STATUS_ACTIVE, Collections.emptyList(), null, + PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS); + mDataNetworkUT.sendMessage(8 /*EVENT_DATA_STATE_CHANGED*/, new AsyncResult( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, List.of(response), null)); + processAllMessages(); + + // Verify precise data connection state not posted again + pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(3)).notifyDataConnection(pdcsCaptor.capture()); + } + + @Test + public void testValidationStatus_FlagDisabled() throws Exception { + // network validation flag disabled + when(mFeatureFlags.networkValidation()).thenReturn(false); + setupIwlanDataNetwork(); + + // precise data connection state posted for setup data call response + ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor = + ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(2)).notifyDataConnection(pdcsCaptor.capture()); + + // data state updated with network validation status + DataCallResponse response = createDataCallResponse(123, + DataCallResponse.LINK_STATUS_ACTIVE, Collections.emptyList(), null, + PreciseDataConnectionState.NETWORK_VALIDATION_SUCCESS); + mDataNetworkUT.sendMessage(8 /*EVENT_DATA_STATE_CHANGED*/, new AsyncResult( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, List.of(response), null)); + processAllMessages(); + + // Verify updated validation status at precise data connection state not posted due to flag + // disabled + pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(2)).notifyDataConnection(pdcsCaptor.capture()); + List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues(); + assertThat(pdcsList.get(1).getNetworkValidationStatus()) + .isEqualTo(PreciseDataConnectionState.NETWORK_VALIDATION_UNSUPPORTED); + } + + private void setupIwlanDataNetwork() throws Exception { + // setup iwlan data network over ims + doReturn(mIwlanNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + eq(NetworkRegistrationInfo.DOMAIN_PS), + eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + + NetworkRequestList networkRequestList = new NetworkRequestList(); + networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) + .build(), mPhone)); + setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123); + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mImsDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + DataAllowedReason.NORMAL, mDataNetworkCallback); + replaceInstance(DataNetwork.class, "mDataCallSessionStats", + mDataNetworkUT, mDataCallSessionStats); + processAllMessages(); + } + + private void createImsDataNetwork(boolean isMmtel) throws Exception { + NetworkRequestList networkRequestList = new NetworkRequestList(); + NetworkRequest.Builder builder = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + if (isMmtel) builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); + networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone)); + + setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123); + + mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(), + mDataServiceManagers, mImsDataProfile, networkRequestList, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + DataAllowedReason.NORMAL, mDataNetworkCallback); + replaceInstance(DataNetwork.class, "mDataCallSessionStats", + mDataNetworkUT, mDataCallSessionStats); + processAllMessages(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java index 27271dfe56..e556cb877e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.ContentValues; @@ -65,6 +66,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -80,8 +82,13 @@ public class DataProfileManagerTest extends TelephonyTest { private static final String IMS_APN = "IMS_APN"; private static final String TETHERING_APN = "DUN_APN"; private static final String APN_SET_ID_1_APN = "APN_SET_ID_1_APN"; + private static final String RCS_APN = "RCS_APN"; + private static final String RCS_APN1 = "RCS_APN1"; private static final String APN_SET_ID_1_TETHERING_APN = "APN_SET_ID_1_TETHERING_APN"; private static final String MATCH_ALL_APN_SET_ID_IMS_APN = "MATCH_ALL_APN_SET_ID_IMS_APN"; + private static final String ESIM_BOOTSTRAP_PROVISIONING_APN = "ESIM_BOOTSTRAP_PROVISIONING_APN"; + private static final String TEST_BOOTSTRAP_APN = + "TEST_BOOTSTRAP_APN"; private static final String PLMN = "330123"; private static final int DEFAULT_APN_SET_ID = Telephony.Carriers.NO_APN_SET_ID; private static final int APN_SET_ID_1 = 1; @@ -131,6 +138,8 @@ public class DataProfileManagerTest extends TelephonyTest { Telephony.Carriers.CARRIER_ID, Telephony.Carriers.SKIP_464XLAT, Telephony.Carriers.ALWAYS_ON, + Telephony.Carriers.INFRASTRUCTURE_BITMASK, + Telephony.Carriers.ESIM_BOOTSTRAP_PROVISIONING }; private int mPreferredApnSet = 0; @@ -169,7 +178,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, // default internet data profile for RAT CDMA, to test update preferred data profile new Object[]{ @@ -204,7 +215,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 2, // id @@ -238,7 +251,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 3, // id @@ -272,7 +287,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // alwys_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 4, // id @@ -307,7 +324,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, // This APN entry is created to test de-duping. new Object[]{ @@ -343,7 +362,9 @@ public class DataProfileManagerTest extends TelephonyTest { DEFAULT_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 6, // id @@ -378,7 +399,9 @@ public class DataProfileManagerTest extends TelephonyTest { APN_SET_ID_1, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 7, // id @@ -413,7 +436,9 @@ public class DataProfileManagerTest extends TelephonyTest { APN_SET_ID_1, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning }, new Object[]{ 8, // id @@ -448,7 +473,194 @@ public class DataProfileManagerTest extends TelephonyTest { MATCH_ALL_APN_SET_ID, // apn_set_id -1, // carrier_id -1, // skip_464xlat - 0 // always_on + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 0 // esim_bootstrap_provisioning + }, + new Object[]{ + 9, // id + PLMN, // numeric + RCS_APN, // name + RCS_APN, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "rcs", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask + 0, // lingering_network_type_bitmask + DEFAULT_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0, // always_on + 2, // INFRASTRUCTURE_SATELLITE + 0 // esim_bootstrap_provisioning + }, + new Object[]{ + 10, // id + PLMN, // numeric + ESIM_BOOTSTRAP_PROVISIONING_APN, // name + ESIM_BOOTSTRAP_PROVISIONING_APN, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default,supl", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask + 0, // lingering_network_type_bitmask + MATCH_ALL_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0, // always_on + 1, // INFRASTRUCTURE_CELLULAR + 1 // esim_bootstrap_provisioning + }, + new Object[]{ + 11, // id + PLMN, // numeric + IMS_APN, // name + IMS_APN, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "ims", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask + 0, // lingering_network_type_bitmask + MATCH_ALL_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0, // always_on + 1, // INFRASTRUCTURE_SATELLITE + 1 // esim_bootstrap_provisioning + }, + new Object[]{ + 12, // id + PLMN, // numeric + TEST_BOOTSTRAP_APN, // name + TEST_BOOTSTRAP_APN, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask + 0, // lingering_network_type_bitmask + MATCH_ALL_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0, // always_on + 2, // INFRASTRUCTURE_SATELLITE + 1 // esim_bootstrap_provisioning + }, + new Object[]{ + 13, // id + PLMN, // numeric + RCS_APN1, // name + RCS_APN1, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "rcs", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask + 0, // lingering_network_type_bitmask + DEFAULT_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0, // always_on + 2, // INFRASTRUCTURE_SATELLITE + 1 // esim_bootstrap_provisioning } ); @@ -631,7 +843,8 @@ public class DataProfileManagerTest extends TelephonyTest { return null; }).when(mDataProfileManagerCallback).invokeFromExecutor(any(Runnable.class)); mDataProfileManagerUT = new DataProfileManager(mPhone, mDataNetworkController, - mMockedWwanDataServiceManager, Looper.myLooper(), mDataProfileManagerCallback); + mMockedWwanDataServiceManager, Looper.myLooper(), mFeatureFlags, + mDataProfileManagerCallback); ArgumentCaptor<DataNetworkControllerCallback> dataNetworkControllerCallbackCaptor = ArgumentCaptor.forClass(DataNetworkControllerCallback.class); verify(mDataNetworkController).registerDataNetworkControllerCallback( @@ -662,7 +875,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); @@ -673,7 +886,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); @@ -683,7 +896,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(IMS_APN); @@ -692,7 +905,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dp).isNull(); doReturn(new NetworkRegistrationInfo.Builder() @@ -705,7 +918,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_NR, false); + TelephonyManager.NETWORK_TYPE_NR, false, false , false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(TETHERING_APN); } @@ -717,7 +930,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_GSM, false); + TelephonyManager.NETWORK_TYPE_GSM, false, false, false); // Should not find data profile due to RAT incompatible. assertThat(dp).isNull(); } @@ -729,14 +942,14 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); logd("Set setLastSetupTimestamp on " + dataProfile); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); // See if another one can be returned. dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); } @@ -747,7 +960,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -760,7 +973,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addEnterpriseId(2), ConnectivityManager.TYPE_NONE, 0, NetworkRequest.Type.REQUEST), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting()).isNull(); osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -776,7 +989,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -792,7 +1005,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -801,15 +1014,30 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(osAppId.getDifferentiator()).isEqualTo(1); } + @Test + public void testGetDataProfileForSatellite() { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .build(); + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); + DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, + TelephonyManager.NETWORK_TYPE_LTE, true, false, false); + + assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); + assertThat(dp.getApnSetting().getApnName()).isEqualTo(RCS_APN); + } @Test public void testSetPreferredDataProfile() { + doReturn(true).when(mFeatureFlags).refinePreferredDataProfileSelection(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest( new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); dataProfile.setPreferred(true); @@ -817,47 +1045,62 @@ public class DataProfileManagerTest extends TelephonyTest { doReturn(dataProfile).when(internetNetwork).getDataProfile(); doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr))) .when(internetNetwork).getAttachedNetworkRequestList(); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged( + Set.of(internetNetwork)); processAllMessages(); // Test See if the same one can be returned. dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); // Test Another default internet network connected due to RAT changed. Verify the preferred // data profile is updated. DataProfile legacyRatDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_CDMA, false); + tnr, TelephonyManager.NETWORK_TYPE_CDMA, false, false, false); DataNetwork legacyRatInternetNetwork = Mockito.mock(DataNetwork.class); doReturn(legacyRatDataProfile).when(legacyRatInternetNetwork).getDataProfile(); doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr))) .when(legacyRatInternetNetwork).getAttachedNetworkRequestList(); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of( + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged(Set.of( // Because internetNetwork is torn down due to network type mismatch legacyRatInternetNetwork)); processAllMessages(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); - // Test Another supl default internet network temporarily connected. Verify preferred - // doesn't change. - TelephonyNetworkRequest suplTnr = new TelephonyNetworkRequest( + // Test Another dun default internet network temporarily connected. Verify preferred + // doesn't change. Mock DUN | DEFAULT. + TelephonyNetworkRequest dunTnr = new TelephonyNetworkRequest( new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .build(), mPhone); - DataProfile suplDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - suplTnr, TelephonyManager.NETWORK_TYPE_LTE, false); - DataNetwork suplInternetNetwork = Mockito.mock(DataNetwork.class); - doReturn(suplDataProfile).when(suplInternetNetwork).getDataProfile(); - doReturn(new DataNetworkController.NetworkRequestList(List.of(suplTnr))) - .when(suplInternetNetwork).getAttachedNetworkRequestList(); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of( - legacyRatInternetNetwork, suplInternetNetwork)); + DataProfile dunDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); + DataNetwork dunInternetNetwork = Mockito.mock(DataNetwork.class); + doReturn(dunDataProfile).when(dunInternetNetwork).getDataProfile(); + doReturn(new DataNetworkController.NetworkRequestList(List.of(dunTnr))) + .when(dunInternetNetwork).getAttachedNetworkRequestList(); + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged(Set.of( + legacyRatInternetNetwork, dunInternetNetwork)); processAllMessages(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); + + // Test a single dun default internet network temporarily connected. Verify preferred + // doesn't change. Mock DUN | DEFAULT and enforced single connection. + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged( + Set.of(dunInternetNetwork)); + processAllMessages(); + + assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); + + // Test all internet networks disconnected. Verify preferred doesn't change. + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged( + Collections.emptySet()); + + assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); } @Test @@ -933,7 +1176,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile).isNull(); // expect default EIMS when SIM absent @@ -942,7 +1185,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos"); // expect no default IMS when SIM absent @@ -951,7 +1194,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile).isEqualTo(null); // Verify null as initial attached data profile is sent to modem @@ -981,7 +1224,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile).isNull(); // expect default EIMS when SIM absent @@ -990,7 +1233,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos"); // expect no default IMS when SIM absent @@ -999,7 +1242,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile).isEqualTo(null); // Verify in legacy mode, null IA should NOT be sent to modem @@ -1034,7 +1277,7 @@ public class DataProfileManagerTest extends TelephonyTest { new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone), - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN); } @@ -1046,7 +1289,7 @@ public class DataProfileManagerTest extends TelephonyTest { TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); // This should get the merged data profile after deduping. DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); } @@ -1055,6 +1298,7 @@ public class DataProfileManagerTest extends TelephonyTest { DataProfile dataProfile1 = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setEntryName("general") + .setOperatorNumeric("123456") .setApnName("apn") .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_HIPRI) @@ -1075,6 +1319,7 @@ public class DataProfileManagerTest extends TelephonyTest { DataProfile dataProfile2 = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setEntryName("XCAP") + .setOperatorNumeric("123456") .setApnName("apn") .setApnTypeBitmask(ApnSetting.TYPE_XCAP) .setUser("user") @@ -1181,7 +1426,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApn()).isEqualTo("sos"); assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos"); @@ -1198,12 +1443,16 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); DataNetwork internetNetwork = Mockito.mock(DataNetwork.class); doReturn(dataProfile).when(internetNetwork).getDataProfile(); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); + + doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr))) + .when(internetNetwork).getAttachedNetworkRequestList(); + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged( + Set.of(internetNetwork)); processAllMessages(); // After internet connected, preferred APN should be set @@ -1235,7 +1484,8 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); // Test removed data profile(user created after reset) shouldn't show up - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); + mDataNetworkControllerCallback.onConnectedInternetDataNetworksChanged( + Set.of(internetNetwork)); processAllMessages(); //APN reset and removed GENERAL_PURPOSE_APN from APN DB mPreferredApnId = -1; @@ -1264,7 +1514,7 @@ public class DataProfileManagerTest extends TelephonyTest { // The carrier configured data profile should be the preferred APN after APN reset DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); @@ -1277,7 +1527,7 @@ public class DataProfileManagerTest extends TelephonyTest { // The carrier configured data profile should be the preferred APN after APN reset dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE, false); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); } @@ -1342,6 +1592,7 @@ public class DataProfileManagerTest extends TelephonyTest { .setApnSetting(new ApnSetting.Builder() .setEntryName(GENERAL_PURPOSE_APN) .setId(1) + .setOperatorNumeric(PLMN) .setApnName(GENERAL_PURPOSE_APN) .setProxyAddress("") .setMmsProxyAddress("") @@ -1360,6 +1611,7 @@ public class DataProfileManagerTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(DEFAULT_APN_SET_ID) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1395,6 +1647,7 @@ public class DataProfileManagerTest extends TelephonyTest { .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(DEFAULT_APN_SET_ID) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1423,6 +1676,7 @@ public class DataProfileManagerTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(APN_SET_ID_1) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1451,6 +1705,7 @@ public class DataProfileManagerTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(MATCH_ALL_APN_SET_ID) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1486,6 +1741,7 @@ public class DataProfileManagerTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(APN_SET_ID_1) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1514,6 +1770,7 @@ public class DataProfileManagerTest extends TelephonyTest { .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(DEFAULT_APN_SET_ID) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1542,6 +1799,7 @@ public class DataProfileManagerTest extends TelephonyTest { | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) .setMvnoMatchData("") .setApnSetId(MATCH_ALL_APN_SET_ID) + .setInfrastructureBitmask(1) .build()) .build(); @@ -1557,7 +1815,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); // Mark the APN as permanent failed. dp.getApnSetting().setPermanentFailed(true); @@ -1565,7 +1823,8 @@ public class DataProfileManagerTest extends TelephonyTest { // Data profile manager should return a different data profile for setup as the previous // data profile has been marked as permanent failed. assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false)).isNotEqualTo(dp); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false)) + .isNotEqualTo(dp); } @Test @@ -1580,7 +1839,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false); // Mark the APN as permanent failed. dp.getApnSetting().setPermanentFailed(true); @@ -1588,7 +1847,8 @@ public class DataProfileManagerTest extends TelephonyTest { // Since preferred APN is already set, and that data profile was marked as permanent failed, // so this should result in getting nothing. assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE, false)).isNull(); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false)) + .isNull(); } private void changeSimStateTo(@TelephonyManager.SimState int simState) { @@ -1609,6 +1869,98 @@ public class DataProfileManagerTest extends TelephonyTest { // Verify the we can get the previously permanent failed data profile again. assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest( new TelephonyNetworkRequest(request, mPhone), - TelephonyManager.NETWORK_TYPE_LTE, false)).isNotNull(); + TelephonyManager.NETWORK_TYPE_LTE, false, false, false)) + .isNotNull(); + } + + @Test + public void testDifferentNetworkRequestProfilesOnEsimBootStrapProvisioning() { + Mockito.clearInvocations(mDataProfileManagerCallback); + Mockito.clearInvocations(mMockedWwanDataServiceManager); + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + + // SIM inserted + mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget(); + processAllMessages(); + + // expect default profile for internet network request, when esim bootstrap provisioning + // flag is enabled at data profile, during esim bootstrap provisioning + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), mPhone); + DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo( + "ESIM_BOOTSTRAP_PROVISIONING_APN"); + + // expect IMS profile for ims network request, when esim bootstrap provisioning flag + // is enabled at data profile, during esim bootstrap provisioning + tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) + .build(), mPhone); + dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("IMS_APN"); + + // expect no mms profile for mms network request, when esim bootstrap provisioning flag + // is disabled at data profile, during esim bootstrap provisioning + tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .build(), mPhone); + dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false); + assertThat(dataProfile).isEqualTo(null); + + // expect no rcs profile for rcs network request, when esim bootstrap provisioning flag + // is disabled at data profile, during esim bootstrap provisioning + tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .build(), mPhone); + dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false); + assertThat(dataProfile).isEqualTo(null); } + + @Test + public void testEsimBootstrapProvisioningEnabled_MultipleProfile() { + Mockito.clearInvocations(mDataProfileManagerCallback); + Mockito.clearInvocations(mMockedWwanDataServiceManager); + + // SIM inserted + mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget(); + processAllMessages(); + + // expect initial default profile entry selected for internet network request, when + // multiple esim bootstrap provisioning flag is enabled at data profile for same apn + // type + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), mPhone); + DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo( + ESIM_BOOTSTRAP_PROVISIONING_APN); + } + + @Test + public void testInfrastructureProfileOnEsimBootStrapProvisioning() { + Mockito.clearInvocations(mDataProfileManagerCallback); + Mockito.clearInvocations(mMockedWwanDataServiceManager); + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + + // SIM inserted + mDataProfileManagerUT.obtainMessage(3 /* EVENT_SIM_REFRESH */).sendToTarget(); + processAllMessages(); + + // expect initial default profile entry selected for internet network request, when + // multiple esim bootstrap provisioning flag is enabled at data profile for same apn + // type + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .build(), mPhone); + DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_LTE, true, true, false); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(RCS_APN1); + } + } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java index 4a2eb38702..f5981f7316 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java @@ -179,6 +179,7 @@ public class DataProfileTest { assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_MMS)).isFalse(); assertThat(dp.canSatisfy(new int[]{NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS})).isFalse(); + assertThat(dp.canSatisfy(new int[]{NetworkCapabilities.NET_CAPABILITY_RCS})).isFalse(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java index 103b189f7e..2541bd1993 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -33,8 +33,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.Intent; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.AsyncResult; @@ -160,7 +158,8 @@ public class DataRetryManagerTest extends TelephonyTest { mockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, mMockedWlanDataServiceManager); mDataRetryManagerUT = new DataRetryManager(mPhone, mDataNetworkController, - mockedDataServiceManagers, Looper.myLooper(), mDataRetryManagerCallbackMock); + mockedDataServiceManagers, Looper.myLooper(), mFeatureFlags, + mDataRetryManagerCallbackMock); ArgumentCaptor<DataConfigManagerCallback> dataConfigManagerCallbackCaptor = ArgumentCaptor.forClass(DataConfigManagerCallback.class); @@ -342,29 +341,30 @@ public class DataRetryManagerTest extends TelephonyTest { @Test public void testDataSetupUnthrottling() throws Exception { - testDataSetupRetryNetworkSuggestedNeverRetry(); + doReturn(true).when(mFeatureFlags).unthrottleCheckTransport(); + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) + .build(); + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); + DataNetworkController.NetworkRequestList + networkRequestList = new DataNetworkController.NetworkRequestList(tnr); + mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, networkRequestList, 123, + 456); + mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, networkRequestList, 123, + 456); + processAllFutureMessages(); Mockito.clearInvocations(mDataRetryManagerCallbackMock); + DataNetworkController.NetworkRequestList mockNrl = Mockito.mock( DataNetworkController.NetworkRequestList.class); Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); field.setAccessible(true); List<DataRetryEntry> mDataRetryEntries = (List<DataRetryEntry>) field.get(mDataRetryManagerUT); + assertThat(mDataRetryEntries.size()).isEqualTo(2); - // schedule 2 setup retries - DataSetupRetryEntry scheduledRetry1 = new DataSetupRetryEntry.Builder<>() - .setDataProfile(mDataProfile3) - .setNetworkRequestList(mockNrl) - .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setSetupRetryType(1) - .build(); - DataSetupRetryEntry scheduledRetry2 = new DataSetupRetryEntry.Builder<>() - .setNetworkRequestList(mockNrl) - .setDataProfile(mDataProfile3) - .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setSetupRetryType(1) - .build(); - mDataRetryEntries.addAll(List.of(scheduledRetry1, scheduledRetry2)); // Suppose we set the data profile as permanently failed. mDataProfile3.getApnSetting().setPermanentFailed(true); @@ -410,8 +410,21 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); // check mDataProfile3-WWAN retry is cancelled, but not the WLAN - assertThat(scheduledRetry1.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED); - assertThat(scheduledRetry2.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED); + assertThat(mDataRetryEntries.size()).isEqualTo(3); + for (DataRetryEntry retry : mDataRetryEntries) { + DataSetupRetryEntry setupRetry = (DataSetupRetryEntry) retry; + if (setupRetry.transport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + if (setupRetry.retryDelayMillis == 0) { + assertThat(setupRetry.getState()) + .isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED); + } else { + assertThat(setupRetry.getState()) + .isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED); + } + } else { + assertThat(setupRetry.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED); + } + } } @Test @@ -773,6 +786,7 @@ public class DataRetryManagerTest extends TelephonyTest { @Test public void testDataRetryLongTimer() { + doReturn(true).when(mFeatureFlags).useAlarmCallback(); // Rule requires a long timer DataSetupRetryRule retryRule = new DataSetupRetryRule( "capabilities=internet, retry_interval=120000, maximum_retries=2"); @@ -793,16 +807,15 @@ public class DataRetryManagerTest extends TelephonyTest { processAllFutureMessages(); // Verify scheduled via Alarm Manager - ArgumentCaptor<PendingIntent> pendingIntentArgumentCaptor = - ArgumentCaptor.forClass(PendingIntent.class); - verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), - pendingIntentArgumentCaptor.capture()); - - // Verify starts retry attempt after receiving intent - PendingIntent pendingIntent = pendingIntentArgumentCaptor.getValue(); - Intent intent = pendingIntent.getIntent(); - mContext.sendBroadcast(intent); - processAllFutureMessages(); + ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListenerCaptor = + ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class); + verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), any(), any(), any(), + alarmListenerCaptor.capture()); + + // Verify starts retry attempt after alarm fires. + AlarmManager.OnAlarmListener alarmListener = alarmListenerCaptor.getValue(); + alarmListener.onAlarm(); + processAllMessages(); verify(mDataRetryManagerCallbackMock) .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java index 88f642bd85..2ceca0e618 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java @@ -155,7 +155,7 @@ public class DataServiceManagerTest extends TelephonyTest { message); waitAndVerifyResult(message, DataServiceCallback.RESULT_SUCCESS); verify(mSimulatedCommandsVerifier).setupDataCall(anyInt(), any(DataProfile.class), - anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), + anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); } @@ -168,7 +168,7 @@ public class DataServiceManagerTest extends TelephonyTest { message); waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); verify(mSimulatedCommandsVerifier, never()).setupDataCall(anyInt(), any(DataProfile.class), - anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), + anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); } @@ -199,7 +199,7 @@ public class DataServiceManagerTest extends TelephonyTest { mDataServiceManagerUT.setInitialAttachApn(mGeneralPurposeDataProfile, false, message); waitAndVerifyResult(message, DataServiceCallback.RESULT_SUCCESS); verify(mSimulatedCommandsVerifier).setInitialAttachApn(any(DataProfile.class), - anyBoolean(), any(Message.class)); + any(Message.class)); } @Test @@ -209,7 +209,7 @@ public class DataServiceManagerTest extends TelephonyTest { mDataServiceManagerUT.setInitialAttachApn(mGeneralPurposeDataProfile, false, message); waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); verify(mSimulatedCommandsVerifier, never()).setInitialAttachApn(any(DataProfile.class), - anyBoolean(), any(Message.class)); + any(Message.class)); } @Test @@ -218,7 +218,7 @@ public class DataServiceManagerTest extends TelephonyTest { Message message = mHandler.obtainMessage(1234); mDataServiceManagerUT.setDataProfile(List.of(mGeneralPurposeDataProfile), false, message); waitAndVerifyResult(message, DataServiceCallback.RESULT_SUCCESS); - verify(mSimulatedCommandsVerifier).setDataProfile(any(DataProfile[].class), anyBoolean(), + verify(mSimulatedCommandsVerifier).setDataProfile(any(DataProfile[].class), any(Message.class)); } @@ -229,7 +229,7 @@ public class DataServiceManagerTest extends TelephonyTest { mDataServiceManagerUT.setDataProfile(List.of(mGeneralPurposeDataProfile), false, message); waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); verify(mSimulatedCommandsVerifier, never()).setDataProfile(any(DataProfile[].class), - anyBoolean(), any(Message.class)); + any(Message.class)); } @Test @@ -267,4 +267,20 @@ public class DataServiceManagerTest extends TelephonyTest { waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); verify(mSimulatedCommandsVerifier, never()).cancelHandover(any(Message.class), anyInt()); } + + @Test + public void testRequestValidation_ServiceNotBound() throws Exception { + createDataServiceManager(false); + Message message = mHandler.obtainMessage(1234); + mDataServiceManagerUT.requestValidation(123, message); + waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + + @Test + public void testRequestValidation_ServiceBound() throws Exception { + createDataServiceManager(true); + Message message = mHandler.obtainMessage(1234); + mDataServiceManagerUT.requestValidation(123, message); + waitAndVerifyResult(message, DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java index 20cb73a68e..fc1bf0da85 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java @@ -29,7 +29,9 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.annotation.NonNull; import android.os.Looper; +import android.os.Message; import android.os.PersistableBundle; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; @@ -49,6 +51,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -178,4 +182,26 @@ public class DataSettingsManagerTest extends TelephonyTest { callback.onUserDataEnabledChanged(true, "callingPackage"); verify(mPhone).notifyDataEnabled(true, TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); } + + @Test + public void testNotifyDataEnabledFromNewValidSubId() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + mDataSettingsManagerUT.registerCallback( + new DataSettingsManagerCallback(mDataSettingsManagerUT::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + latch.countDown(); + } + }); + + Message.obtain(mDataSettingsManagerUT, 4 /* EVENT_SUBSCRIPTIONS_CHANGED */, -1) + .sendToTarget(); + Message.obtain(mDataSettingsManagerUT, 4 /* EVENT_SUBSCRIPTIONS_CHANGED */, 2) + .sendToTarget(); + processAllMessages(); + + assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java index 22cdaae64f..e1e238ec7c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify; import android.content.Intent; import android.database.ContentObserver; import android.net.NetworkAgent; +import android.net.NetworkCapabilities; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; @@ -51,8 +52,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -154,12 +154,14 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { DataNetworkControllerCallback dataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getAllValues().get(0); - if (isConnected) { - List<DataNetwork> dataprofile = new ArrayList<>(); - dataNetworkControllerCallback.onInternetDataNetworkConnected(dataprofile); - } else { - dataNetworkControllerCallback.onInternetDataNetworkDisconnected(); + DataNetwork network = mock(DataNetwork.class); + NetworkCapabilities netCaps = new NetworkCapabilities(); + doReturn(netCaps).when(network).getNetworkCapabilities(); + if (!isConnected) { + // A network that doesn't need to be tracked for validation + netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } + dataNetworkControllerCallback.onConnectedInternetDataNetworksChanged(Set.of(network)); processAllMessages(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java index 3fa5ba577f..719862ae7a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -269,12 +269,14 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse("data allowed", mDataAllowed[0]); setSlotIndexToSubId(1, 1); + clearInvocations(mAutoDataSwitchController); mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); + verify(mAutoDataSwitchController).notifySubscriptionsMappingChanged(); clearInvocations(mActivePhoneSwitchHandler); assertFalse("data allowed", mDataAllowed[0]); assertTrue("data not allowed", mDataAllowed[1]); @@ -291,8 +293,10 @@ public class PhoneSwitcherTest extends TelephonyTest { // 3 lose default via sub->phone change setSlotIndexToSubId(0, 2); + clearInvocations(mAutoDataSwitchController); mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); + verify(mAutoDataSwitchController).notifySubscriptionsMappingChanged(); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); @@ -634,7 +638,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // A higher priority event occurring E.g. Phone1 has active IMS call on LTE. doReturn(mImsPhone).when(mPhone).getImsPhone(); doReturn(true).when(mPhone).isUserDataEnabled(); - doReturn(true).when(mPhone).isDataAllowed(); + doReturn(true).when(mDataSettingsManager).isDataEnabled(); mockImsRegTech(0, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mPhone); @@ -886,7 +890,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); @@ -915,7 +919,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Dialing shouldn't trigger switch because we give modem time to deal with the dialing call // first. Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); @@ -949,7 +953,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); @@ -976,7 +980,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); @@ -1005,7 +1009,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); doReturn(true).when(mPhone).isUserDataEnabled(); - doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); @@ -1099,7 +1103,6 @@ public class PhoneSwitcherTest extends TelephonyTest { } @Test - @SmallTest public void testDataEnabledChangedDuringVoiceCall() throws Exception { doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(); @@ -1137,6 +1140,18 @@ public class PhoneSwitcherTest extends TelephonyTest { } @Test + public void testRoamingToggle() throws Exception { + initialize(); + setSlotIndexToSubId(0, 1); + + mDataSettingsManagerCallbacks.get(0).onDataRoamingEnabledChanged(true); + processAllMessages(); + + verify(mAutoDataSwitchController).evaluateAutoDataSwitch(AutoDataSwitchController + .EVALUATION_REASON_DATA_SETTINGS_CHANGED); + } + + @Test @SmallTest public void testNetworkRequestOnNonDefaultData() throws Exception { doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); @@ -1706,6 +1721,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 2.2 Auto switch feature is enabled doReturn(true).when(mPhone2).isDataAllowed(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); // 3.1 No default network doReturn(null).when(mConnectivityManager).getNetworkCapabilities(any()); @@ -1785,7 +1801,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private void notifyDataEnabled(boolean dataEnabled) { doReturn(true).when(mPhone).isUserDataEnabled(); doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(); - doReturn(dataEnabled).when(mPhone2).isDataAllowed(); + doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(); mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(dataEnabled, 123 , ""); if (mDataSettingsManagerCallbacks.size() > 1) { mDataSettingsManagerCallbacks.get(1).onDataEnabledChanged(dataEnabled, 123, ""); @@ -1868,7 +1884,8 @@ public class PhoneSwitcherTest extends TelephonyTest { initializeConnManagerMock(); initializeConfigMock(); - mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); + mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper(), + mFeatureFlags); Field field = PhoneSwitcher.class.getDeclaredField("mDataSettingsManagerCallbacks"); field.setAccessible(true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java index 9752885b62..26a9fde815 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java @@ -87,6 +87,24 @@ public class TelephonyNetworkRequestTest extends TelephonyTest { .setMaxConnsTime(789) .build(); + private static final ApnSetting RCS_APN_SETTING = new ApnSetting.Builder() + .setId(2165) + .setOperatorNumeric("12345") + .setEntryName("rcs") + .setApnName("rcs") + .setUser("user") + .setPassword("passwd") + .setApnTypeBitmask(ApnSetting.TYPE_RCS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .setNetworkTypeBitmask(0) + .setProfileId(1234) + .setMaxConns(321) + .setWaitTime(456) + .setMaxConnsTime(789) + .build(); + @Before public void setUp() throws Exception { logd("TelephonyNetworkRequestTest +Setup!"); @@ -211,6 +229,20 @@ public class TelephonyNetworkRequestTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) .build(); assertThat(internetRequest.canBeSatisfiedBy(caps)).isTrue(); + + TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest( + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .build(), mPhone); + caps = new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .build(); + assertThat(rcsRequest.canBeSatisfiedBy(caps)).isTrue(); } @Test @@ -223,17 +255,25 @@ public class TelephonyNetworkRequestTest extends TelephonyTest { new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) .build(), mPhone); + TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest( + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS) + .build(), mPhone); DataProfile internetDataProfile = new DataProfile.Builder() .setApnSetting(INTERNET_APN_SETTING) .build(); DataProfile mmsDataProfile = new DataProfile.Builder() .setApnSetting(MMS_APN_SETTING) .build(); + DataProfile rcsDataProfile = new DataProfile.Builder() + .setApnSetting(RCS_APN_SETTING) + .build(); assertThat(internetRequest.canBeSatisfiedBy(internetDataProfile)).isTrue(); assertThat(internetRequest.canBeSatisfiedBy(mmsDataProfile)).isFalse(); assertThat(mmsRequest.canBeSatisfiedBy(internetDataProfile)).isFalse(); assertThat(mmsRequest.canBeSatisfiedBy(mmsDataProfile)).isTrue(); + assertThat(rcsRequest.canBeSatisfiedBy(rcsDataProfile)).isTrue(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java index ce59cc6c32..1734244463 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java @@ -20,6 +20,8 @@ import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; import static android.telephony.DomainSelectionService.SCAN_TYPE_NO_PREFERENCE; import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.eq; @@ -31,11 +33,14 @@ import static org.mockito.Mockito.verify; import android.os.AsyncResult; import android.os.CancellationSignal; import android.os.Handler; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.DomainSelectionService; import android.telephony.DomainSelector; import android.telephony.EmergencyRegResult; import android.telephony.TransportSelectorCallback; import android.telephony.WwanSelectorCallback; +import android.telephony.data.ApnSetting; import android.telephony.ims.ImsReasonInfo; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -43,6 +48,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.CallFailCause; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import org.junit.After; import org.junit.Before; @@ -131,19 +137,16 @@ public class DomainSelectionConnectionTest extends TelephonyTest { public void testWwanSelectorCallbackAsync() throws Exception { mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, mDomainSelectionController); - replaceInstance(DomainSelectionConnection.class, "mWwanSelectedExecutor", - mDsc, new Executor() { - public void execute(Runnable command) { - command.run(); - } - }); TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); assertNotNull(transportCallback); + replaceInstance(DomainSelectionConnection.class, "mLooper", + mDsc, mTestableLooper.getLooper()); Consumer<WwanSelectorCallback> consumer = Mockito.mock(Consumer.class); transportCallback.onWwanSelected(consumer); + processAllMessages(); verify(consumer).accept(any()); } @@ -171,6 +174,7 @@ public class DomainSelectionConnectionTest extends TelephonyTest { Consumer<EmergencyRegResult> consumer = Mockito.mock(Consumer.class); wwanCallback.onRequestEmergencyNetworkScan(preferredNetworks, scanType, null, consumer); + processAllMessages(); ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class); ArgumentCaptor<Integer> eventCaptor = ArgumentCaptor.forClass(Integer.class); @@ -220,11 +224,13 @@ public class DomainSelectionConnectionTest extends TelephonyTest { CancellationSignal signal = new CancellationSignal(); wwanCallback.onRequestEmergencyNetworkScan(new ArrayList<>(), SCAN_TYPE_NO_PREFERENCE, signal, Mockito.mock(Consumer.class)); + processAllMessages(); verify(mPhone).registerForEmergencyNetworkScan(any(), anyInt(), any()); verify(mPhone).triggerEmergencyNetworkScan(any(), anyInt(), any()); signal.cancel(); + processAllMessages(); verify(mPhone).cancelEmergencyNetworkScan(eq(false), any()); } @@ -290,6 +296,31 @@ public class DomainSelectionConnectionTest extends TelephonyTest { verify(domainSelector).finishSelection(); } + @Test + @SmallTest + public void testQualifiedNetworkTypesChanged() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + List<QualifiedNetworks> networksList = new ArrayList<>(); + + assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList)) + .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.IWLAN })); + + assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList)) + .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + networksList.clear(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.EUTRAN })); + + assertThat(mDsc.getPreferredTransport(ApnSetting.TYPE_EMERGENCY, networksList)) + .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + } + private DomainSelectionService.SelectionAttributes getSelectionAttributes( int slotId, int subId, int selectorType, boolean isEmergency, boolean exited, int callFailCause, String callId, String number, diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java index 2c65b50303..eaf11a4e4a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java @@ -83,6 +83,8 @@ public class DomainSelectionResolverTest extends TelephonyTest { @Test @SmallTest public void testGetInstance() throws IllegalStateException { + DomainSelectionResolver.setDomainSelectionResolver(null); + assertThrows(IllegalStateException.class, () -> { DomainSelectionResolver.getInstance(); }); @@ -137,12 +139,37 @@ public class DomainSelectionResolverTest extends TelephonyTest { @Test @SmallTest + public void testGetDomainSelectionConnectionWhenImsPhoneNull() throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + mDsResolver.initialize(mDsService); + when(mPhone.getImsPhone()).thenReturn(null); + + assertNull(mDsResolver.getDomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true)); + } + + @Test + @SmallTest public void testGetDomainSelectionConnectionWhenImsNotAvailable() throws Exception { setUpResolver(true, RADIO_HAL_VERSION_2_1); mDsResolver.initialize(mDsService); when(mPhone.isImsAvailable()).thenReturn(false); + when(mPhone.getImsPhone()).thenReturn(mImsPhone); - assertNull(mDsResolver.getDomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true)); + assertNull(mDsResolver.getDomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, false)); + } + + @Test + @SmallTest + public void testGetDomainSelectionConnectionWhenImsNotAvailableForEmergencyCall() + throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + setUpController(); + mDsResolver.initialize(mDsService); + when(mPhone.isImsAvailable()).thenReturn(false); + when(mPhone.getImsPhone()).thenReturn(mImsPhone); + + assertNotNull(mDsResolver.getDomainSelectionConnection(mPhone, + SELECTOR_TYPE_CALLING, true)); } @Test @@ -152,6 +179,7 @@ public class DomainSelectionResolverTest extends TelephonyTest { setUpController(); mDsResolver.initialize(mDsService); when(mPhone.isImsAvailable()).thenReturn(true); + when(mPhone.getImsPhone()).thenReturn(mImsPhone); assertNotNull(mDsResolver.getDomainSelectionConnection( mPhone, SELECTOR_TYPE_CALLING, true)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java index 0c64b82072..d0b2fce83b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -17,7 +17,6 @@ package com.android.internal.telephony.domainselection; import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; -import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN; import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED; import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; @@ -38,25 +37,34 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.DomainSelectionService; import android.telephony.EmergencyRegResult; import android.telephony.NetworkRegistrationInfo; import android.telephony.TransportSelectorCallback; import android.telephony.WwanSelectorCallback; +import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import com.android.internal.telephony.emergency.EmergencyStateTracker; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; @RunWith(AndroidTestingRunner.class) @@ -96,7 +104,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest public void testSelectDomainWifi() throws Exception { - doReturn(TRANSPORT_TYPE_WLAN).when(mAnm).getPreferredTransport(anyInt()); + doReturn(TRANSPORT_TYPE_WWAN).when(mAnm).getPreferredTransport(anyInt()); replaceInstance(EmergencyCallDomainSelectionConnection.class, "mEmergencyStateTracker", mEcDsc, mEmergencyStateTracker); @@ -120,6 +128,21 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { mTransportCallback.onWlanSelected(true); + ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor<Integer> msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + + assertFalse(future.isDone()); + + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.IWLAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); + assertTrue(future.isDone()); assertEquals((long) DOMAIN_NON_3GPP_PS, (long) future.get()); verify(mEmergencyStateTracker).onEmergencyTransportChanged( diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java index 25ccecbebc..3b6d0c3c38 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java @@ -29,19 +29,23 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.DomainSelectionService; import android.telephony.DomainSelector; import android.telephony.NetworkRegistrationInfo; +import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.AccessNetworksManager.QualifiedNetworks; import com.android.internal.telephony.emergency.EmergencyStateTracker; import org.junit.After; @@ -51,6 +55,8 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; /** @@ -151,9 +157,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mPhone).notifyEmergencyDomainSelected( eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.IWLAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); Handler handler = handlerCaptor.getValue(); Integer msg = msgCaptor.getValue(); - handler.handleMessage(Message.obtain(handler, msg.intValue())); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); processAllMessages(); assertTrue(future.isDone()); @@ -214,9 +224,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mPhone).notifyEmergencyDomainSelected( eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.IWLAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); Handler handler = handlerCaptor.getValue(); Integer msg = msgCaptor.getValue(); - handler.handleMessage(Message.obtain(handler, msg.intValue())); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); processAllMessages(); assertTrue(future.isDone()); @@ -273,9 +287,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mPhone).notifyEmergencyDomainSelected( eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.EUTRAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); Handler handler = handlerCaptor.getValue(); Integer msg = msgCaptor.getValue(); - handler.handleMessage(Message.obtain(handler, msg.intValue())); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); processAllMessages(); assertTrue(future.isDone()); @@ -364,9 +382,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mPhone).notifyEmergencyDomainSelected( eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.EUTRAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); Handler handler = handlerCaptor.getValue(); Integer msg = msgCaptor.getValue(); - handler.handleMessage(Message.obtain(handler, msg.intValue())); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); processAllMessages(); assertTrue(future.isDone()); @@ -445,9 +467,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mPhone).notifyEmergencyDomainSelected( eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + List<QualifiedNetworks> networksList = new ArrayList<>(); + networksList.add(new QualifiedNetworks(ApnSetting.TYPE_EMERGENCY, + new int[]{ AccessNetworkType.EUTRAN })); + AsyncResult ar = new AsyncResult(null, networksList, null); Handler handler = handlerCaptor.getValue(); Integer msg = msgCaptor.getValue(); - handler.handleMessage(Message.obtain(handler, msg.intValue())); + handler.handleMessage(Message.obtain(handler, msg.intValue(), ar)); processAllMessages(); mDsConnection.finishSelection(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java index 2a8e4e2ca3..fff1b68e75 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -56,6 +56,8 @@ import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -205,6 +207,83 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } /** + * Test that the EmergencyStateTracker turns off satellite modem, performs a DDS switch and + * sets emergency mode switch when we are not roaming and the carrier only supports SUPL over + * the data plane. + */ + @Test + @SmallTest + public void startEmergencyCall_satelliteEnabled_turnOnRadioSwitchDdsAndSetEmergencyMode() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones and set radio on + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + true /* isRadioOn */); + when(mSST.isRadioOn()).thenReturn(true); + // Satellite enabled + when(mSatelliteController.isSatelliteEnabled()).thenReturn(true); + + setConfigForDdsSwitch(testPhone, null, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "150"); + // Spy is used to capture consumer in delayDialForDdsSwitch + EmergencyStateTracker spyEst = spy(emergencyStateTracker); + CompletableFuture<Integer> unused = spyEst.startEmergencyCall(testPhone, TEST_CALL_ID, + false); + + // startEmergencyCall should trigger radio on + ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor + .forClass(RadioOnStateListener.Callback.class); + verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), + eq(false), eq(0)); + // isOkToCall() should return true once satellite modem is off + assertFalse(callback.getValue() + .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false)); + when(mSatelliteController.isSatelliteEnabled()).thenReturn(false); + assertTrue(callback.getValue() + .isOkToCall(testPhone, ServiceState.STATE_IN_SERVICE, false)); + // Once radio on is complete, trigger delay dial + callback.getValue().onComplete(null, true); + ArgumentCaptor<Consumer<Boolean>> completeConsumer = ArgumentCaptor + .forClass(Consumer.class); + verify(spyEst).switchDdsDelayed(eq(testPhone), completeConsumer.capture()); + verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(testPhone.getPhoneId()), + eq(150) /* extensionTime */, any()); + // After dds switch completes successfully, set emergency mode + completeConsumer.getValue().accept(true); + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); + } + + /** + * Test that if startEmergencyCall fails to turn off satellite modem, then it's future completes + * with {@link DisconnectCause#SATELLITE_ENABLED}. + */ + @Test + @SmallTest + public void startEmergencyCall_satelliteOffFails_returnsDisconnectCauseSatelliteEnabled() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones and set radio on + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + true /* isRadioOn */); + // Satellite enabled + when(mSatelliteController.isSatelliteEnabled()).thenReturn(true); + + CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // startEmergencyCall should trigger satellite modem off + ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor + .forClass(RadioOnStateListener.Callback.class); + verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), + eq(false), eq(0)); + // Verify future completes with DisconnectCause.POWER_OFF if radio not ready + CompletableFuture<Void> unused = future.thenAccept((result) -> { + assertEquals((Integer) result, (Integer) DisconnectCause.SATELLITE_ENABLED); + }); + callback.getValue().onComplete(null, false /* isRadioReady */); + } + + /** * Test that the EmergencyStateTracker does not perform a DDS switch when the carrier supports * control-plane fallback. Radio is set to on so RadioOnHelper not triggered. */ @@ -597,6 +676,252 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } /** + * Test that once endCall() for IMS call is called and we enter ECM, then we exit ECM + * after the specified timeout. + */ + @Test + @SmallTest + public void endCall_entersEcm_thenExitsEcmAfterTimeoutImsCall() throws Exception { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); + CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.onEmergencyCallDomainUpdated( + PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + + processAllMessages(); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + + Context mockContext = mock(Context.class); + replaceInstance(EmergencyStateTracker.class, "mContext", + emergencyStateTracker, mockContext); + processAllFutureMessages(); + + ArgumentCaptor<TelephonyCallback> callbackCaptor = + ArgumentCaptor.forClass(TelephonyCallback.class); + + verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()), + any(), callbackCaptor.capture()); + + TelephonyCallback callback = callbackCaptor.getValue(); + + assertNotNull(callback); + + // Verify exitEmergencyMode() is called after timeout + verify(testPhone).exitEmergencyMode(any(Message.class)); + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + verify(mTelephonyManagerProxy).unregisterTelephonyCallback(eq(callback)); + } + + /** + * Test that startEmergencyCall() is called right after exiting ECM on the same slot. + */ + @Test + @SmallTest + public void exitEcm_thenDialEmergencyCallOnTheSameSlotRightAfter() throws Exception { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + emergencyStateTracker.setPdnDisconnectionTimeoutMs(0); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); + + verify(testPhone, times(0)).setEmergencyMode(anyInt(), any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + processAllMessages(); + + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.onEmergencyCallDomainUpdated( + PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + + processAllMessages(); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + + Context mockContext = mock(Context.class); + replaceInstance(EmergencyStateTracker.class, "mContext", + emergencyStateTracker, mockContext); + processAllFutureMessages(); + + ArgumentCaptor<TelephonyCallback> callbackCaptor = + ArgumentCaptor.forClass(TelephonyCallback.class); + + verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()), + any(), callbackCaptor.capture()); + + TelephonyCallback callback = callbackCaptor.getValue(); + + assertNotNull(callback); + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + verify(mTelephonyManagerProxy, times(0)).unregisterTelephonyCallback(eq(callback)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), + any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + replaceInstance(EmergencyStateTracker.class, "mContext", emergencyStateTracker, mContext); + + // dial on the same slot + unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + verify(mTelephonyManagerProxy, times(1)).unregisterTelephonyCallback(eq(callback)); + verify(testPhone, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), + any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + } + + /** + * Test that startEmergencyCall() is called right after exiting ECM on the other slot. + */ + @Test + @SmallTest + public void exitEcm_thenDialEmergencyCallOnTheOtherSlotRightAfter() throws Exception { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + emergencyStateTracker.setPdnDisconnectionTimeoutMs(0); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); + + verify(testPhone, times(0)).setEmergencyMode(anyInt(), any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + processAllMessages(); + + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.onEmergencyCallDomainUpdated( + PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + + processAllMessages(); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + + Context mockContext = mock(Context.class); + replaceInstance(EmergencyStateTracker.class, "mContext", + emergencyStateTracker, mockContext); + processAllFutureMessages(); + + ArgumentCaptor<TelephonyCallback> callbackCaptor = + ArgumentCaptor.forClass(TelephonyCallback.class); + + verify(mTelephonyManagerProxy).registerTelephonyCallback(eq(testPhone.getSubId()), + any(), callbackCaptor.capture()); + + TelephonyCallback callback = callbackCaptor.getValue(); + + assertNotNull(callback); + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + verify(mTelephonyManagerProxy, times(0)).unregisterTelephonyCallback(eq(callback)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), + any(Message.class)); + verify(testPhone, times(0)).exitEmergencyMode(any(Message.class)); + + Phone phone1 = getPhone(1); + verify(phone1, times(0)).setEmergencyMode(anyInt(), any(Message.class)); + verify(phone1, times(0)).exitEmergencyMode(any(Message.class)); + + replaceInstance(EmergencyStateTracker.class, "mContext", emergencyStateTracker, mContext); + + // dial on the other slot + unused = emergencyStateTracker.startEmergencyCall(phone1, TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + verify(mTelephonyManagerProxy, times(1)).unregisterTelephonyCallback(eq(callback)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(testPhone, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), + any(Message.class)); + verify(testPhone, times(1)).exitEmergencyMode(any(Message.class)); + verify(phone1, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(phone1, times(0)).exitEmergencyMode(any(Message.class)); + } + + /** + * Test that once endCall() is called and we enter ECM, then we exit ECM when turning on + * airplane mode. + */ + @Test + @SmallTest + public void endCall_entersEcm_thenExitsEcmWhenTurnOnAirplaneMode() { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); + CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + + processAllMessages(); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + + emergencyStateTracker.onCellularRadioPowerOffRequested(); + + // Verify exitEmergencyMode() is called. + verify(testPhone).exitEmergencyMode(any(Message.class)); + assertFalse(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyMode()); + } + + /** * Test that after exitEmergencyCallbackMode() is called, the correct intents are sent and * emergency mode is exited on the modem. */ @@ -829,6 +1154,34 @@ public class EmergencyStateTrackerTest extends TelephonyTest { @Test @SmallTest + public void testRecoverNormalInCellularWhenVoWiFiConnected() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Call startEmergencyCall() to set testPhone + CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Set emergency transport + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WLAN); + + // Set call properties + emergencyStateTracker.onEmergencyCallPropertiesChanged( + android.telecom.Connection.PROPERTY_WIFI, TEST_CALL_ID); + + verify(testPhone, times(0)).cancelEmergencyNetworkScan(anyBoolean(), any()); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + verify(testPhone, times(1)).cancelEmergencyNetworkScan(eq(true), any()); + } + + @Test + @SmallTest public void testStartEmergencySms() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); @@ -868,7 +1221,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); verify(phone0).exitEmergencyMode(any(Message.class)); assertFalse(emergencyStateTracker.isInEmergencyMode()); @@ -1315,7 +1668,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertTrue(emergencyStateTracker.isInEmergencyMode()); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); processAllMessages(); assertFalse(emergencyStateTracker.isInEmergencyMode()); @@ -1352,7 +1705,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); assertTrue(emergencyStateTracker.isInEmergencyMode()); @@ -1399,7 +1752,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertTrue(emergencyStateTracker.isInEcm()); assertFalse(emergencyStateTracker.isInEmergencyCall()); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); processAllMessages(); verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class)); @@ -1454,7 +1807,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { emergencyStateTracker.onEmergencyTransportChanged( EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); processAllMessages(); // Enter emergency callback mode and emergency mode changed by SMS end. @@ -1501,7 +1854,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); - emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + emergencyStateTracker.endSms(TEST_SMS_ID, true); assertTrue(emergencyStateTracker.isInEmergencyMode()); @@ -1521,6 +1874,88 @@ public class EmergencyStateTrackerTest extends TelephonyTest { verify(phone0).exitEmergencyMode(any(Message.class)); } + @Test + @SmallTest + public void testSaveKeyEmergencyCallbackModeSupportedBool() { + mContextFixture.getCarrierConfigBundle().putBoolean( + CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + Phone phone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + false /* isRadioOn */); + when(phone.getSubId()).thenReturn(1); + setEcmSupportedConfig(phone, true); + + EmergencyStateTracker testEst = setupEmergencyStateTracker( + false /* isSuplDdsSwitchRequiredForEmergencyCall */); + + assertNotNull(testEst.startEmergencyCall(phone, TEST_CALL_ID, false)); + + ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + + verify(cfgManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + + CarrierConfigManager.CarrierConfigChangeListener carrierConfigChangeListener = + listenerArgumentCaptor.getAllValues().get(0); + + // Verify carrier config for valid subscription + assertTrue(testEst.isEmergencyCallbackModeSupported()); + + // SIM removed + when(phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + setEcmSupportedConfig(phone, false); + + // Verify default config for invalid subscription + assertFalse(testEst.isEmergencyCallbackModeSupported()); + + // Insert SIM again + when(phone.getSubId()).thenReturn(1); + setEcmSupportedConfig(phone, true); + + // onCarrierConfigChanged with valid subscription + carrierConfigChangeListener.onCarrierConfigChanged( + phone.getPhoneId(), phone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + + // SIM removed again + when(phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + setEcmSupportedConfig(phone, false); + + // onCarrierConfigChanged with invalid subscription + carrierConfigChangeListener.onCarrierConfigChanged( + phone.getPhoneId(), phone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + + // Verify saved config for valid subscription + assertTrue(testEst.isEmergencyCallbackModeSupported()); + + // Insert SIM again, but emergency callback mode not supported + when(phone.getSubId()).thenReturn(1); + setEcmSupportedConfig(phone, false); + + // onCarrierConfigChanged with valid subscription + carrierConfigChangeListener.onCarrierConfigChanged( + phone.getPhoneId(), phone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + + // Verify carrier config for valid subscription + assertFalse(testEst.isEmergencyCallbackModeSupported()); + + // SIM removed again + when(phone.getSubId()).thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + setEcmSupportedConfig(phone, false); + + // onCarrierConfigChanged with invalid subscription + carrierConfigChangeListener.onCarrierConfigChanged( + phone.getPhoneId(), phone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + + // Verify saved config for valid subscription + assertFalse(testEst.isEmergencyCallbackModeSupported()); + } + private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java index 1c1ca0feff..17a428bd51 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java @@ -36,11 +36,14 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; import java.util.ArrayList; import java.util.concurrent.Executor; @@ -56,15 +59,18 @@ public class GsmMmiCodeTest extends TelephonyTest { private static final String TEST_DIAL_STRING_NON_EMERGENCY_NUMBER = "11976"; private GsmMmiCode mGsmMmiCode; private GsmCdmaPhone mGsmCdmaPhoneUT; + @Mock private FeatureFlags mFeatureFlags; private final Executor mExecutor = Runnable::run; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mFeatureFlags = Mockito.mock(FeatureFlags.class); doReturn(mExecutor).when(mContext).getMainExecutor(); mGsmCdmaPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0, - PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); + PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager, + mFeatureFlags); setCarrierSupportsCallerIdVerticalServiceCodesCarrierConfig(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index d0a20949bb..bfa702cf40 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -94,6 +94,7 @@ import android.telephony.ims.ImsConferenceState; import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; +import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.SrvccCall; import android.telephony.ims.aidl.IImsTrafficSessionCallback; @@ -125,7 +126,6 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.d2d.RtpTransport; -import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker.VtDataUsageProvider; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -160,6 +160,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private Bundle mBundle = new Bundle(); private static final int SUB_0 = 0; @Nullable private VtDataUsageProvider mVtDataUsageProvider; + private ProvisioningManager.Callback mConfigCallback; // Mocked classes private ArgumentCaptor<Set<RtpHeaderExtensionType>> mRtpHeaderExtensionTypeCaptor; @@ -172,7 +173,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private INetworkStatsProviderCallback mVtDataUsageProviderCb; private ImsPhoneCallTracker.ConnectorFactory mConnectorFactory; private CommandsInterface mMockCi; - private DomainSelectionResolver mDomainSelectionResolver; private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private final Executor mExecutor = Runnable::run; @@ -240,7 +240,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState(); doReturn(mImsCallProfile).when(mImsManager).createCallProfile(anyInt(), anyInt()); mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); - mDomainSelectionResolver = mock(DomainSelectionResolver.class); doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); @@ -279,13 +278,14 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { return mMockConnector; }).when(mConnectorFactory).create(any(), anyInt(), anyString(), any(), any()); - DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); - doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + doReturn(false) + .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges(); // Capture CarrierConfigChangeListener to emulate the carrier config change notification ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); - mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run); + mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run, + mFeatureFlags); verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); @@ -309,6 +309,12 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mMockConnector).connect(); mConnectorListener.connectionReady(mImsManager, SUB_0); + + final ArgumentCaptor<ProvisioningManager.Callback> configCallbackCaptor = + ArgumentCaptor.forClass(ProvisioningManager.Callback.class); + verify(mImsConfig).addConfigCallback(configCallbackCaptor.capture()); + mConfigCallback = configCallbackCaptor.getValue(); + assertNotNull(mConfigCallback); } @After @@ -2641,6 +2647,73 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); } + @Test + public void testProvisioningItemAndUpdateImsServiceConfigWithFeatureEnabled() { + doReturn(true) + .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges(); + + // Receive a subscription loaded and IMS connection ready indication. + mContextFixture.getCarrierConfigBundle().putBoolean( + CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + sendCarrierConfigChanged(); + processAllMessages(); + verify(mImsManager, times(1)).updateImsServiceConfig(); + + logd("deliver provisioning items"); + mConfigCallback.onProvisioningIntChanged(27, 2); + mConfigCallback.onProvisioningIntChanged(28, 1); + mConfigCallback.onProvisioningIntChanged(10, 1); + mConfigCallback.onProvisioningIntChanged(11, 1); + mConfigCallback.onProvisioningStringChanged(12, "msg.pc.t-mobile.com"); + mConfigCallback.onProvisioningIntChanged(26, 0); + mConfigCallback.onProvisioningIntChanged(66, 0); + + logd("proc provisioning items"); + processAllFutureMessages(); + + // updateImsServiceConfig is called with below 2 events. + // 1. CarrierConfig + // 2. ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28), ProvisioningManager + // .KEY_VOLTE_PROVISIONING_STATUS(10) and ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11) + verify(mImsManager, times(2)).updateImsServiceConfig(); + } + + + @Test + public void testProvisioningItemAndUpdateImsServiceConfigWithFeatureDisabled() { + doReturn(false) + .when(mFeatureFlags).updateImsServiceByGatheringProvisioningChanges(); + + // Receive a subscription loaded and IMS connection ready indication. + mContextFixture.getCarrierConfigBundle().putBoolean( + CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + sendCarrierConfigChanged(); + processAllMessages(); + verify(mImsManager, times(1)).updateImsServiceConfig(); + + logd("deliver provisioning items"); + mConfigCallback.onProvisioningIntChanged(27, 2); + //ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28) call updateImsServiceConfig. + mConfigCallback.onProvisioningIntChanged(28, 1); + //ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS(10) call updateImsServiceConfig. + mConfigCallback.onProvisioningIntChanged(10, 1); + //ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11) call updateImsServiceConfig. + mConfigCallback.onProvisioningIntChanged(11, 1); + mConfigCallback.onProvisioningStringChanged(12, "msg.pc.t-mobile.com"); + mConfigCallback.onProvisioningIntChanged(26, 0); + mConfigCallback.onProvisioningIntChanged(66, 0); + + logd("proc provisioning items"); + processAllFutureMessages(); + + // updateImsServiceConfig is called with below 4 events. + // 1. CarrierConfig + // 2. ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE(28) + // 3. ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS(10) + // 4. ProvisioningManager.KEY_VT_PROVISIONING_STATUS(11) + verify(mImsManager, times(4)).updateImsServiceConfig(); + } + private void sendCarrierConfigChanged() { mCarrierConfigChangeListener.onCarrierConfigChanged(mPhone.getPhoneId(), mPhone.getSubId(), TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java index a657ba2988..21d79a9dd1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java @@ -28,6 +28,7 @@ import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import org.junit.After; import org.junit.Before; @@ -42,6 +43,8 @@ public class ImsPhoneFactoryTest extends TelephonyTest { private ImsPhone mImsPhoneUT; private ImsPhoneFactoryHandler mImsPhoneFactoryHandler; + private FeatureFlags mFeatureFlags; + private final Executor mExecutor = Runnable::run; private class ImsPhoneFactoryHandler extends HandlerThread { @@ -51,7 +54,8 @@ public class ImsPhoneFactoryTest extends TelephonyTest { } @Override public void onLooperPrepared() { - mImsPhoneUT = ImsPhoneFactory.makePhone(mContext, mPhoneNotifier, mPhone); + mImsPhoneUT = ImsPhoneFactory.makePhone(mContext, mPhoneNotifier, mPhone, + mFeatureFlags); setReady(true); } } @@ -60,6 +64,7 @@ public class ImsPhoneFactoryTest extends TelephonyTest { public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mPhoneNotifier = mock(PhoneNotifier.class); + mFeatureFlags = mock(FeatureFlags.class); doReturn(mExecutor).when(mContext).getMainExecutor(); mImsPhoneFactoryHandler = new ImsPhoneFactoryHandler(getClass().getSimpleName()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java index d8173a22b1..a833da0e57 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java @@ -35,6 +35,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import org.junit.After; import org.junit.Before; @@ -57,6 +58,7 @@ public class ImsPhoneMmiCodeTest extends TelephonyTest { // Mocked classes private ServiceState mServiceState; + private FeatureFlags mFeatureFlags; private final Executor mExecutor = Runnable::run; @@ -64,12 +66,14 @@ public class ImsPhoneMmiCodeTest extends TelephonyTest { public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mServiceState = mock(ServiceState.class); + mFeatureFlags = mock(FeatureFlags.class); + doReturn(mExecutor).when(mContext).getMainExecutor(); doReturn(mPhone).when(mPhone).getDefaultPhone(); doReturn(mServiceState).when(mPhone).getServiceState(); doReturn(false).when(mServiceState).getVoiceRoaming(); doReturn(false).when(mPhone).supportsConversionOfCdmaCallerIdMmiCodesWhileRoaming(); - mImsPhoneUT = new ImsPhone(mContext, mNotifier, mPhone); + mImsPhoneUT = new ImsPhone(mContext, mNotifier, mPhone, mFeatureFlags); setCarrierSupportsCallerIdVerticalServiceCodesCarrierConfig(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java index cd9d9ad1b1..f491041e9d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -24,6 +24,8 @@ import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_PREFERRED; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_RAT_BLOCK; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_3G; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; @@ -97,6 +99,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.domainselection.DomainSelectionResolver; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.SS; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -122,9 +125,9 @@ public class ImsPhoneTest extends TelephonyTest { private ImsPhoneCall mBackgroundCall; private ImsPhoneCall mRingingCall; private Handler mTestHandler; - private DomainSelectionResolver mDomainSelectionResolver; Connection mConnection; ImsUtInterface mImsUtInterface; + private FeatureFlags mFeatureFlags; private final Executor mExecutor = Runnable::run; @@ -148,9 +151,7 @@ public class ImsPhoneTest extends TelephonyTest { mTestHandler = mock(Handler.class); mConnection = mock(Connection.class); mImsUtInterface = mock(ImsUtInterface.class); - mDomainSelectionResolver = mock(DomainSelectionResolver.class); - doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); - DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); + mFeatureFlags = mock(FeatureFlags.class); mImsCT.mForegroundCall = mForegroundCall; mImsCT.mBackgroundCall = mBackgroundCall; @@ -162,7 +163,8 @@ public class ImsPhoneTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isVoiceCapable(); - mImsPhoneUT = new ImsPhone(mContext, mNotifier, mPhone, (c, p) -> mImsManager, true); + mImsPhoneUT = new ImsPhone(mContext, mNotifier, mPhone, (c, p) -> mImsManager, true, + mFeatureFlags); mDoesRilSendMultipleCallRing = TelephonyProperties.ril_sends_multiple_call_ring() .orElse(true); @@ -194,7 +196,6 @@ public class ImsPhoneTest extends TelephonyTest { public void tearDown() throws Exception { mImsPhoneUT = null; mBundle = null; - DomainSelectionResolver.setDomainSelectionResolver(null); super.tearDown(); } @@ -1111,6 +1112,37 @@ public class ImsPhoneTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(""); } + @Test + @SmallTest + public void testClearPhoneNumberForSourceIms() { + doReturn(true).when(mFeatureFlags) + .clearCachedImsPhoneNumberWhenDeviceLostImsRegistration(); + + // In reality the method under test runs in phone process so has MODIFY_PHONE_STATE + mContextFixture.addCallingOrSelfPermission(MODIFY_PHONE_STATE); + int subId = 1; + doReturn(subId).when(mPhone).getSubId(); + doReturn(new SubscriptionInfoInternal.Builder().setId(subId).setSimSlotIndex(0) + .setCountryIso("gb").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(subId); + + // 1. Two valid phone number; 1st is set. + Uri[] associatedUris = new Uri[] { + Uri.parse("sip:+447539447777@ims.x.com"), + Uri.parse("tel:+447539446666") + }; + mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); + + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539447777"); + + mImsPhoneUT.clearPhoneNumberForSourceIms(); + + verify(mSubscriptionManagerService).setNumberFromIms(subId, ""); + + // Clean up + mContextFixture.addCallingOrSelfPermission(""); + } + /** * Verifies that valid radio technology is passed to RIL * when IMS registration state changes to registered. @@ -1366,13 +1398,14 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); - // duplicated notification with the same suggested action + // verifies that duplicated notification with the same suggested action is invoked registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); - // verify that there is no update in the SimulatedCommands - assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); // unregistered with repeated error registrationCallback.onUnregistered(reasonInfo, @@ -1390,14 +1423,15 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); - // duplicated notification with the same suggested action + // verfies that duplicated notification with the same suggested action is invoked registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT, REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); - // verify that there is no update in the SimulatedCommands - assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); // unregistered with temporary error registrationCallback.onUnregistered(reasonInfo, @@ -1408,6 +1442,19 @@ public class ImsPhoneTest extends TelephonyTest { && regInfo[1] == REGISTRATION_TECH_LTE && regInfo[2] == SUGGESTED_ACTION_NONE); + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // verfies that duplicated notification with temporary error is discarded + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_NONE, REGISTRATION_TECH_LTE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + // verifies that reason codes except ImsReasonInfo.CODE_REGISTRATION_ERROR are discarded. reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE, ImsReasonInfo.CODE_UNSPECIFIED, ""); @@ -1425,7 +1472,7 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); - // duplicated notification with the same suggested action + // verifies that duplicated notification with temporary error is discarded registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_NONE, REGISTRATION_TECH_NR); regInfo = mSimulatedCommands.getImsRegistrationInfo(); @@ -1434,6 +1481,81 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); } + /** + * Verifies that valid state and reason is passed to RIL with RAT suggested actions + * when IMS registration state changes to unregistered. + */ + @Test + @SmallTest + public void testUpdateImsRegistrationInfoWithRatSuggestedAction() { + doReturn(true).when(mFeatureFlags) + .addRatRelatedSuggestedActionToImsRegistration(); + + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + + int[] regInfo = mSimulatedCommands.getImsRegistrationInfo(); + assertNotNull(regInfo); + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + RegistrationManager.RegistrationCallback registrationCallback = + mImsPhoneUT.getImsMmTelRegistrationCallback(); + + ImsReasonInfo reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, + ImsReasonInfo.CODE_UNSPECIFIED, ""); + + // unregistered with rat block + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_RAT_BLOCK, + REGISTRATION_TECH_LTE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // verfies that duplicated notification with the same suggested action is invoked + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_RAT_BLOCK, + REGISTRATION_TECH_LTE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK); + + // unregistered with rat block clear + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK, + REGISTRATION_TECH_LTE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // verfies that duplicated notification with the same suggested action is invoked + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK, + REGISTRATION_TECH_LTE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK); + } + @Test @SmallTest public void testImsDialArgsBuilderFromForAlternateService() { diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java index 504782bb46..df8bd85d0c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java @@ -23,6 +23,7 @@ import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPAB import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT; import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO; import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; @@ -40,6 +41,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.telephony.NetworkRegistrationInfo; import android.telephony.TelephonyManager; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability; @@ -67,6 +69,13 @@ public class ImsStatsTest extends TelephonyTest { private static final int CARRIER1_ID = 1; private static final int CARRIER2_ID = 1187; + private ImsRegistrationAttributes mWwanAttributes = + new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_LTE).build(); + private ImsRegistrationAttributes mIwlanAttributes = + new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_IWLAN).build(); + private ImsRegistrationAttributes mCrossSimAttributes = + new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_CROSS_SIM).build(); + @MmTelCapability private static final int CAPABILITY_TYPE_ALL = MmTelCapabilities.CAPABILITY_TYPE_VOICE @@ -164,7 +173,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_SMS, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL)); @@ -211,7 +220,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_SMS, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); @@ -258,7 +267,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_UT, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN); + mImsStats.onImsRegistered(mIwlanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); @@ -287,6 +296,35 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest + public void conclude_registeredVoiceOnly_crossSimCalling() throws Exception { + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VOICE, + REGISTRATION_TECH_CROSS_SIM, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onImsRegistered(mCrossSimAttributes); + mImsStats.onImsCapabilitiesChanged( + REGISTRATION_TECH_CROSS_SIM, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); + + mImsStats.incTimeMillis(2000L); + mImsStats.conclude(); + + // Duration should be counted + ArgumentCaptor<ImsRegistrationStats> captor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture()); + ImsRegistrationStats stats = captor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat); + assertEquals(true, stats.isIwlanCrossSim); + assertEquals(2000L, stats.registeredMillis); + assertEquals(2000L, stats.voiceCapableMillis); + assertEquals(2000L, stats.voiceAvailableMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest public void conclude_notRegistered() throws Exception { // IMS over LTE mImsStats.onSetFeatureResponse( @@ -308,12 +346,190 @@ public class ImsStatsTest extends TelephonyTest { mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL)); + mImsStats.onImsUnregistered( + new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); + mImsStats.incTimeMillis(2000L); mImsStats.conclude(); - // No atom should be generated + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = + ArgumentCaptor.forClass(ImsRegistrationTermination.class); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); + assertEquals(CARRIER1_ID, termination.carrierId); + assertFalse(termination.isMultiSim); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); + assertTrue(termination.setupFailed); + assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); + assertEquals(999, termination.extraCode); + assertEquals("Timeout", termination.extraMessage); + + // Registering duration should be counted + ArgumentCaptor<ImsRegistrationStats> statsCaptor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture()); + ImsRegistrationStats stats = statsCaptor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat); + assertEquals(2000L, stats.unregisteredMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void conclude_registering() throws Exception { + // IMS over LTE + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VOICE, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VIDEO, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_UT, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_SMS, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onImsCapabilitiesChanged( + REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL)); + + mImsStats.onImsRegistering(TRANSPORT_TYPE_WLAN); + + mImsStats.incTimeMillis(2000L); + mImsStats.conclude(); + + // Registering duration should be counted ArgumentCaptor<ImsRegistrationStats> captor = ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture()); + ImsRegistrationStats stats = captor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat); + assertEquals(2000L, stats.registeringMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void conclude_serviceStateChanged_afterRatUnknown() throws Exception { + // IMS over LTE + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VOICE, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VIDEO, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_UT, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_SMS, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onImsCapabilitiesChanged( + REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL)); + + mImsStats.onImsUnregistered( + new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); + + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN) + .when(mServiceState) + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); + + mImsStats.incTimeMillis(2000L); + + doReturn(TelephonyManager.NETWORK_TYPE_LTE) + .when(mServiceState) + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); + mImsStats.conclude(); + + // Atom with termination info should be generated + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = + ArgumentCaptor.forClass(ImsRegistrationTermination.class); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); + assertEquals(CARRIER1_ID, termination.carrierId); + assertFalse(termination.isMultiSim); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); + assertTrue(termination.setupFailed); + assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); + assertEquals(999, termination.extraCode); + assertEquals("Timeout", termination.extraMessage); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void conclude_serviceStateChanged_afterRatLte() throws Exception { + // IMS over LTE + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VOICE, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_VIDEO, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_UT, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onSetFeatureResponse( + CAPABILITY_TYPE_SMS, + REGISTRATION_TECH_LTE, + ProvisioningManager.PROVISIONING_VALUE_ENABLED); + mImsStats.onImsCapabilitiesChanged( + REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL)); + + mImsStats.onImsUnregistered( + new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); + + doReturn(TelephonyManager.NETWORK_TYPE_LTE) + .when(mServiceState) + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); + + mImsStats.incTimeMillis(2000L); + + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN) + .when(mServiceState) + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); + mImsStats.conclude(); + + // Atom with termination info and durations should be generated + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = + ArgumentCaptor.forClass(ImsRegistrationTermination.class); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); + assertEquals(CARRIER1_ID, termination.carrierId); + assertFalse(termination.isMultiSim); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); + assertTrue(termination.setupFailed); + assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); + assertEquals(999, termination.extraCode); + assertEquals("Timeout", termination.extraMessage); + + ArgumentCaptor<ImsRegistrationStats> statsCaptor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture()); + ImsRegistrationStats stats = statsCaptor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat); + assertEquals(2000L, stats.unregisteredMillis); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -324,7 +540,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.incTimeMillis(2000L); mImsStats.onImsCapabilitiesChanged( @@ -359,7 +575,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); @@ -398,7 +614,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_SMS, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_SMS)); @@ -437,7 +653,7 @@ public class ImsStatsTest extends TelephonyTest { CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE, ProvisioningManager.PROVISIONING_VALUE_ENABLED); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.incTimeMillis(2000L); mImsStats.onSetFeatureResponse( @@ -468,11 +684,11 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void onImsRegistered_differentTech() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.incTimeMillis(2000L); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN); + mImsStats.onImsRegistered(mIwlanAttributes); mImsStats.incTimeMillis(2000L); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); // At this point, the first 2 registrations should have their durations counted ArgumentCaptor<ImsRegistrationStats> captor = @@ -510,6 +726,62 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest + public void onImsRegistered_afterImsRegistering() throws Exception { + mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN); + mImsStats.incTimeMillis(2000L); + mImsStats.onImsRegistered(mWwanAttributes); + + // Registering duration should be counted + ArgumentCaptor<ImsRegistrationStats> captor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture()); + ImsRegistrationStats stats = captor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat); + assertEquals(0L, stats.registeredMillis); + assertEquals(2000L, stats.registeringMillis); + } + + @Test + @SmallTest + public void onImsRegistering_afterImsUnregistered() throws Exception { + doReturn(TelephonyManager.NETWORK_TYPE_LTE) + .when(mServiceState) + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); + + mImsStats.onImsUnregistered( + new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); + mImsStats.incTimeMillis(2000L); + mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN); + + // Atom with termination info should be generated + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = + ArgumentCaptor.forClass(ImsRegistrationTermination.class); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); + assertEquals(CARRIER1_ID, termination.carrierId); + assertFalse(termination.isMultiSim); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); + assertTrue(termination.setupFailed); + assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); + assertEquals(999, termination.extraCode); + assertEquals("Timeout", termination.extraMessage); + + ArgumentCaptor<ImsRegistrationStats> statsCaptor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture()); + ImsRegistrationStats stats = statsCaptor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat); + assertEquals(2000L, stats.unregisteredMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest public void onImsUnregistered_setupFailure() throws Exception { mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); @@ -521,7 +793,7 @@ public class ImsStatsTest extends TelephonyTest { ImsRegistrationTermination termination = captor.getValue(); assertEquals(CARRIER1_ID, termination.carrierId); assertFalse(termination.isMultiSim); - assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); assertTrue(termination.setupFailed); assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); assertEquals(999, termination.extraCode); @@ -532,16 +804,26 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void onImsUnregistered_setupFailureWithProgress() throws Exception { - mImsStats.onImsRegistering(REGISTRATION_TECH_LTE); + mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN); mImsStats.incTimeMillis(2000L); mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); - // Atom with termination info should be generated - ArgumentCaptor<ImsRegistrationTermination> captor = + // Atom with termination info and durations should be generated + ArgumentCaptor<ImsRegistrationStats> statsCaptor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture()); + ImsRegistrationStats stats = statsCaptor.getValue(); + assertEquals(CARRIER1_ID, stats.carrierId); + assertEquals(0, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat); + assertEquals(0L, stats.registeredMillis); + assertEquals(2000L, stats.registeringMillis); + + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = ArgumentCaptor.forClass(ImsRegistrationTermination.class); - verify(mPersistAtomsStorage).addImsRegistrationTermination(captor.capture()); - ImsRegistrationTermination termination = captor.getValue(); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); assertEquals(CARRIER1_ID, termination.carrierId); assertFalse(termination.isMultiSim); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); @@ -555,7 +837,7 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void onImsUnregistered_afterRegistered() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.incTimeMillis(2000L); mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); @@ -604,7 +886,7 @@ public class ImsStatsTest extends TelephonyTest { ImsRegistrationTermination termination = captor.getValue(); assertEquals(CARRIER1_ID, termination.carrierId); assertFalse(termination.isMultiSim); - assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); assertTrue(termination.setupFailed); assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); assertEquals(0, termination.extraCode); @@ -630,7 +912,7 @@ public class ImsStatsTest extends TelephonyTest { ImsRegistrationTermination termination = captor.getValue(); assertEquals(CARRIER1_ID, termination.carrierId); assertFalse(termination.isMultiSim); - assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd); assertTrue(termination.setupFailed); assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); assertEquals(0, termination.extraCode); @@ -757,9 +1039,7 @@ public class ImsStatsTest extends TelephonyTest { } } - @Test - @SmallTest - public void onImsUnregistered_multiSim() throws Exception { + void secondSimMockSetup() { doReturn(mSecondImsPhone).when(mSecondPhone).getImsPhone(); doReturn(mSecondPhone).when(mSecondImsPhone).getDefaultPhone(); doReturn(1).when(mSecondPhone).getPhoneId(); @@ -776,8 +1056,14 @@ public class ImsStatsTest extends TelephonyTest { // Reusing service state tracker from phone 0 for simplicity doReturn(mSST).when(mSecondPhone).getServiceStateTracker(); doReturn(mSST).when(mSecondImsPhone).getServiceStateTracker(); + } + + @Test + @SmallTest + public void onImsUnregistered_multiSim() throws Exception { + secondSimMockSetup(); mImsStats = new TestableImsStats(mSecondImsPhone); - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.incTimeMillis(2000L); mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); @@ -815,6 +1101,42 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest + public void onImsUnregistered_crossSim() throws Exception { + secondSimMockSetup(); + mImsStats = new TestableImsStats(mSecondImsPhone); + mImsStats.onImsRegistered(mCrossSimAttributes); + mImsStats.incTimeMillis(2000L); + mImsStats.onImsUnregistered( + new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout")); + + // Atom with termination info and durations should be generated + ArgumentCaptor<ImsRegistrationStats> statsCaptor = + ArgumentCaptor.forClass(ImsRegistrationStats.class); + verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture()); + ImsRegistrationStats stats = statsCaptor.getValue(); + assertEquals(CARRIER2_ID, stats.carrierId); + assertEquals(1, stats.simSlotIndex); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat); + assertEquals(true, stats.isIwlanCrossSim); + assertEquals(2000L, stats.registeredMillis); + + ArgumentCaptor<ImsRegistrationTermination> terminationCaptor = + ArgumentCaptor.forClass(ImsRegistrationTermination.class); + verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture()); + ImsRegistrationTermination termination = terminationCaptor.getValue(); + assertEquals(CARRIER2_ID, termination.carrierId); + assertTrue(termination.isMultiSim); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, termination.ratAtEnd); + assertEquals(true, termination.isIwlanCrossSim); + assertFalse(termination.setupFailed); + assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode); + assertEquals(999, termination.extraCode); + assertEquals("Timeout", termination.extraMessage); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest public void getImsVoiceRadioTech_noRegistration() throws Exception { // Do nothing @@ -824,7 +1146,7 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void getImsVoiceRadioTech_noVoiceRegistration() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_SMS)); @@ -834,7 +1156,7 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void getImsVoiceRadioTech_cellularRegistration() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); @@ -844,7 +1166,7 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void getImsVoiceRadioTech_wifiRegistration() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WLAN); + mImsStats.onImsRegistered(mIwlanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); @@ -853,8 +1175,18 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest + public void getImsVoiceRadioTech_crossSimRegistration() throws Exception { + mImsStats.onImsRegistered(mCrossSimAttributes); + mImsStats.onImsCapabilitiesChanged( + REGISTRATION_TECH_CROSS_SIM, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); + + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, mImsStats.getImsVoiceRadioTech()); + } + + @Test + @SmallTest public void getImsVoiceRadioTech_unregistered() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); mImsStats.onImsUnregistered( @@ -873,17 +1205,14 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void getImsVoiceRadioTech_serviceStateChanged() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); - doReturn( - new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState( - NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build()) + + doReturn(TelephonyManager.NETWORK_TYPE_NR) .when(mServiceState) - .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); assertEquals(TelephonyManager.NETWORK_TYPE_NR, mImsStats.getImsVoiceRadioTech()); } @@ -891,17 +1220,14 @@ public class ImsStatsTest extends TelephonyTest { @Test @SmallTest public void getImsVoiceRadioTech_serviceStateChanged_wlan() throws Exception { - mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN); + mImsStats.onImsRegistered(mWwanAttributes); mImsStats.onImsCapabilitiesChanged( REGISTRATION_TECH_IWLAN, new MmTelCapabilities(CAPABILITY_TYPE_VOICE)); - doReturn( - new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState( - NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build()) + + doReturn(TelephonyManager.NETWORK_TYPE_IWLAN) .when(mServiceState) - .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + .getDataNetworkType(); + mImsStats.onServiceStateChanged(mServiceState); assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, mImsStats.getImsVoiceRadioTech()); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java index d4e1b86cda..0e1135e3f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java @@ -23,6 +23,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE; import static com.android.internal.telephony.TelephonyStatsLog.SUPPORTED_RADIO_ACCESS_FAMILY; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION; +import static com.android.internal.telephony.util.TelephonyUtils.IS_DEBUGGABLE; import static com.google.common.truth.Truth.assertThat; @@ -51,6 +52,7 @@ import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccPort; +import com.android.internal.telephony.uicc.UiccProfile; import com.android.internal.telephony.uicc.UiccSlot; import org.junit.After; @@ -66,6 +68,8 @@ public class MetricsCollectorTest extends TelephonyTest { .setCoolDownMillis(24L * 3600L * 1000L) .build(); private static final long MIN_COOLDOWN_MILLIS = 23L * 3600L * 1000L; + private static final long CELL_SERVICE_MIN_COOLDOWN_MILLIS = + IS_DEBUGGABLE ? 4L * 60L * 1000L : MIN_COOLDOWN_MILLIS; private static final long MIN_CALLS_PER_BUCKET = 5L; // NOTE: these fields are currently 32-bit internally and padded to 64-bit by TelephonyManager @@ -91,6 +95,7 @@ public class MetricsCollectorTest extends TelephonyTest { private UiccCard mActiveCard; private UiccPort mActivePort; private ServiceStateStats mServiceStateStats; + private VonrHelper mVonrHelper; private MetricsCollector mMetricsCollector; @@ -103,8 +108,10 @@ public class MetricsCollectorTest extends TelephonyTest { mActiveCard = mock(UiccCard.class); mActivePort = mock(UiccPort.class); mServiceStateStats = mock(ServiceStateStats.class); + mVonrHelper = mock(VonrHelper.class); mMetricsCollector = - new MetricsCollector(mContext, mPersistAtomsStorage, mDeviceStateHelper); + new MetricsCollector(mContext, mPersistAtomsStorage, + mDeviceStateHelper, mVonrHelper); doReturn(mSST).when(mSecondPhone).getServiceStateTracker(); doReturn(mServiceStateStats).when(mSST).getServiceStateStats(); } @@ -119,6 +126,9 @@ public class MetricsCollectorTest extends TelephonyTest { @SmallTest public void onPullAtom_simSlotState_bothSimPresent() { // these have been tested extensively in SimSlotStateTest, here we verify atom generation + UiccProfile activeProfile = mock(UiccProfile.class); + doReturn(4).when(activeProfile).getNumApplications(); + doReturn(activeProfile).when(mActivePort).getUiccProfile(); doReturn(true).when(mPhysicalSlot).isActive(); doReturn(CardState.CARDSTATE_PRESENT).when(mPhysicalSlot).getCardState(); doReturn(false).when(mPhysicalSlot).isEuicc(); @@ -126,7 +136,6 @@ public class MetricsCollectorTest extends TelephonyTest { doReturn(CardState.CARDSTATE_PRESENT).when(mEsimSlot).getCardState(); doReturn(true).when(mEsimSlot).isEuicc(); doReturn(mActiveCard).when(mEsimSlot).getUiccCard(); - doReturn(4).when(mActivePort).getNumApplications(); doReturn(new UiccPort[] {mActivePort}).when(mActiveCard).getUiccPortList(); doReturn(new UiccSlot[] {mPhysicalSlot, mEsimSlot}).when(mUiccController).getUiccSlots(); doReturn(mPhysicalSlot).when(mUiccController).getUiccSlot(eq(0)); @@ -395,7 +404,8 @@ public class MetricsCollectorTest extends TelephonyTest { assertThat(actualAtoms).hasSize(0); assertThat(result).isEqualTo(StatsManager.PULL_SKIP); - verify(mPersistAtomsStorage, times(1)).getCellularServiceStates(eq(MIN_COOLDOWN_MILLIS)); + verify(mPersistAtomsStorage, times(1)).getCellularServiceStates( + eq(CELL_SERVICE_MIN_COOLDOWN_MILLIS)); verifyNoMoreInteractions(mPersistAtomsStorage); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java index dc9be1c579..e03dfe42ed 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java @@ -107,6 +107,7 @@ public class PerSimStatusTest extends TelephonyTest { .when(imsMmTelManager1) .getVoWiFiRoamingModeSetting(); doReturn(false).when(imsMmTelManager1).isVtSettingEnabled(); + doReturn(true).when(imsMmTelManager1).isCrossSimCallingEnabled(); doReturn(false).when(mPhone).getDataRoamingEnabled(); doReturn(1L) .when(mPhone) @@ -152,6 +153,7 @@ public class PerSimStatusTest extends TelephonyTest { .when(imsMmTelManager2) .getVoWiFiRoamingModeSetting(); doReturn(true).when(imsMmTelManager2).isVtSettingEnabled(); + doReturn(false).when(imsMmTelManager2).isCrossSimCallingEnabled(); doReturn(false).when(mSecondPhone).getDataRoamingEnabled(); doReturn(1L) .when(mSecondPhone) @@ -191,6 +193,8 @@ public class PerSimStatusTest extends TelephonyTest { perSimStatus1.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus1.unmeteredNetworks); assertEquals(false, perSimStatus1.vonrEnabled); + assertEquals(true, perSimStatus1.crossSimCallingEnabled); + assertEquals(101, perSimStatus2.carrierId); assertEquals(1, perSimStatus2.phoneNumberSourceUicc); assertEquals(2, perSimStatus2.phoneNumberSourceCarrier); @@ -210,6 +214,7 @@ public class PerSimStatusTest extends TelephonyTest { perSimStatus2.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus2.unmeteredNetworks); assertEquals(false, perSimStatus2.vonrEnabled); + assertEquals(false, perSimStatus2.crossSimCallingEnabled); } @Test @@ -279,6 +284,7 @@ public class PerSimStatusTest extends TelephonyTest { perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); assertEquals(true, perSimStatus.vonrEnabled); + assertEquals(false, perSimStatus.crossSimCallingEnabled); } @Test @@ -340,6 +346,7 @@ public class PerSimStatusTest extends TelephonyTest { perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); assertEquals(true, perSimStatus.vonrEnabled); + assertEquals(false, perSimStatus.crossSimCallingEnabled); } @Test @@ -397,5 +404,6 @@ public class PerSimStatusTest extends TelephonyTest { perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); assertEquals(true, perSimStatus.vonrEnabled); + assertEquals(false, perSimStatus.crossSimCallingEnabled); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java index 3307813d74..0cbb0f67c7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java @@ -1017,7 +1017,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { mSatelliteProvision1.isCanceled = false; mSatelliteProvision2 = new SatelliteProvision(); - mSatelliteProvision2.resultCode = SatelliteProtoEnums.SATELLITE_SERVICE_NOT_PROVISIONED; + mSatelliteProvision2.resultCode = + SatelliteProtoEnums.SATELLITE_SERVICE_NOT_PROVISIONED; mSatelliteProvision2.provisioningTimeSec = 0; mSatelliteProvision2.isProvisionRequest = false; mSatelliteProvision2.isCanceled = true; @@ -1033,6 +1034,9 @@ public class PersistAtomsStorageTest extends TelephonyTest { mSatelliteSosMessageRecommender1.isImsRegistered = false; mSatelliteSosMessageRecommender1.cellularServiceState = TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE; + mSatelliteSosMessageRecommender1.isMultiSim = true; + mSatelliteSosMessageRecommender1.recommendingHandoverType = 1; + mSatelliteSosMessageRecommender1.isSatelliteAllowedInCurrentLocation = true; mSatelliteSosMessageRecommender1.count = 1; mSatelliteSosMessageRecommender2 = new SatelliteSosMessageRecommender(); @@ -1041,6 +1045,9 @@ public class PersistAtomsStorageTest extends TelephonyTest { mSatelliteSosMessageRecommender2.isImsRegistered = true; mSatelliteSosMessageRecommender2.cellularServiceState = TelephonyProtoEnums.SERVICE_STATE_POWER_OFF; + mSatelliteSosMessageRecommender2.isMultiSim = false; + mSatelliteSosMessageRecommender2.recommendingHandoverType = 0; + mSatelliteSosMessageRecommender2.isSatelliteAllowedInCurrentLocation = true; mSatelliteSosMessageRecommender2.count = 1; mSatelliteSosMessageRecommenders = @@ -4688,7 +4695,11 @@ public class PersistAtomsStorageTest extends TelephonyTest { == expectedStats.isDisplaySosMessageSent && stats.countOfTimerStarted == expectedStats.countOfTimerStarted && stats.isImsRegistered == expectedStats.isImsRegistered - && stats.cellularServiceState == expectedStats.cellularServiceState) { + && stats.cellularServiceState == expectedStats.cellularServiceState + && stats.isMultiSim == expectedStats.isMultiSim + && stats.recommendingHandoverType == expectedStats.recommendingHandoverType + && stats.isSatelliteAllowedInCurrentLocation + == expectedStats.isSatelliteAllowedInCurrentLocation) { actualCount = stats.count; } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java index 22032ae88a..959b643aec 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java @@ -196,7 +196,8 @@ public class SatelliteStatsTest extends TelephonyTest { public void onSatelliteProvisionMetrics_withAtoms() throws Exception { SatelliteStats.SatelliteProvisionParams param = new SatelliteStats.SatelliteProvisionParams.Builder() - .setResultCode(SatelliteProtoEnums.SATELLITE_SERVICE_PROVISION_IN_PROGRESS) + .setResultCode( + SatelliteProtoEnums.SATELLITE_SERVICE_PROVISION_IN_PROGRESS) .setProvisioningTimeSec(5 * 1000) .setIsProvisionRequest(true) .setIsCanceled(false) @@ -224,6 +225,9 @@ public class SatelliteStatsTest extends TelephonyTest { .setCountOfTimerStarted(5) .setImsRegistered(false) .setCellularServiceState(TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE) + .setIsMultiSim(false) + .setRecommendingHandoverType(0) + .setIsSatelliteAllowedInCurrentLocation(true) .build(); mSatelliteStats.onSatelliteSosMessageRecommender(param); @@ -237,6 +241,10 @@ public class SatelliteStatsTest extends TelephonyTest { assertEquals(param.getCountOfTimerStarted(), stats.countOfTimerStarted); assertEquals(param.isImsRegistered(), stats.isImsRegistered); assertEquals(param.getCellularServiceState(), stats.cellularServiceState); + assertEquals(param.isMultiSim(), stats.isMultiSim); + assertEquals(param.getRecommendingHandoverType(), stats.recommendingHandoverType); + assertEquals(param.isSatelliteAllowedInCurrentLocation(), + stats.isSatelliteAllowedInCurrentLocation); verifyNoMoreInteractions(mPersistAtomsStorage); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java index f186f987f2..c66cfa7999 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -43,10 +44,12 @@ import android.telephony.Annotation.NetworkType; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; @@ -57,6 +60,9 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.util.Collections; +import java.util.Set; + public class ServiceStateStatsTest extends TelephonyTest { private static final long START_TIME_MILLIS = 2000L; private static final int CARRIER1_ID = 1; @@ -396,12 +402,39 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest + public void onImsVoiceRegistrationChanged_crossSimCalling() throws Exception { + mServiceStateStats.onServiceStateChanged(mServiceState); + mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech(); + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).when(mImsPhone) + .getImsRegistrationTech(); + mServiceStateStats.incTimeMillis(100L); + mServiceStateStats.onImsVoiceRegistrationChanged(); + mServiceStateStats.incTimeMillis(200L); + mServiceStateStats.conclude(); + + ArgumentCaptor<CellularServiceState> captor = + ArgumentCaptor.forClass(CellularServiceState.class); + verify(mPersistAtomsStorage, times(2)) + .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null)); + CellularServiceState state = captor.getAllValues().get(1); + + assertEquals(200L, state.totalTimeMillis); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat); + assertTrue(state.isIwlanCrossSim); + } + + @Test + @SmallTest public void onInternetDataNetworkDisconnected() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); + // Set internet network connected + mServiceStateStats.onConnectedInternetDataNetworksChanged(Set.of(mock(DataNetwork.class))); + clearInvocations(mPersistAtomsStorage); mServiceStateStats.incTimeMillis(100L); - mServiceStateStats.onInternetDataNetworkDisconnected(); + mServiceStateStats.onConnectedInternetDataNetworksChanged(Collections.emptySet()); mServiceStateStats.incTimeMillis(200L); mServiceStateStats.conclude(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SimSlotStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SimSlotStateTest.java index 0a64ee3ec8..c5c672cd8d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/SimSlotStateTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SimSlotStateTest.java @@ -29,6 +29,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccPort; +import com.android.internal.telephony.uicc.UiccProfile; import com.android.internal.telephony.uicc.UiccSlot; import org.junit.After; @@ -71,8 +72,12 @@ public class SimSlotStateTest extends TelephonyTest { doReturn(CardState.CARDSTATE_PRESENT).when(mEsimSlot).getCardState(); doReturn(true).when(mEsimSlot).isEuicc(); - doReturn(0).when(mInactivePort).getNumApplications(); - doReturn(4).when(mActivePort).getNumApplications(); + UiccProfile inactiveProfile = mock(UiccProfile.class); + UiccProfile activeProfile = mock(UiccProfile.class); + doReturn(0).when(inactiveProfile).getNumApplications(); + doReturn(4).when(activeProfile).getNumApplications(); + doReturn(inactiveProfile).when(mInactivePort).getUiccProfile(); + doReturn(activeProfile).when(mActivePort).getUiccProfile(); doReturn(new UiccPort[]{mInactivePort}).when(mInactiveCard).getUiccPortList(); doReturn(new UiccPort[]{mActivePort}).when(mActiveCard).getUiccPortList(); @@ -94,6 +99,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(0, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -108,6 +115,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(0, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -122,6 +131,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(0, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -136,6 +147,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -151,6 +164,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -166,6 +181,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -182,6 +199,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -197,6 +216,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -212,6 +233,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -227,11 +250,31 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(1, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @Test @SmallTest + public void testSingleSim_esimCardWithMultipleProfiles() { + doReturn(mActiveCard).when(mEsimSlot).getUiccCard(); + doReturn(new UiccPort[]{mActivePort, mActivePort}).when(mActiveCard).getUiccPortList(); + setupSingleSim(mEsimSlot); + + SimSlotState state = SimSlotState.getCurrentState(); + boolean isMultiSim = SimSlotState.isMultiSim(); + + assertEquals(1, state.numActiveSlots); + assertEquals(2, state.numActiveSims); + assertEquals(2, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(1, state.numActiveMepSlots); + assertTrue(isMultiSim); + } + + @Test + @SmallTest public void testDsdsSingleSimMode_noSimCard() { setupDualSim(mEmptySlot, mInactiveSlot); @@ -241,6 +284,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -255,6 +300,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -270,6 +317,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -285,6 +334,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(1, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(1, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -300,6 +351,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(0, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -315,6 +368,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @@ -330,11 +385,31 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(1, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); } @Test @SmallTest + public void testDsds_esimCardWithMultipleProfiles() { + doReturn(mActiveCard).when(mEsimSlot).getUiccCard(); + doReturn(new UiccPort[]{mActivePort, mActivePort}).when(mActiveCard).getUiccPortList(); + setupDualSim(mEmptySlot, mEsimSlot); + + SimSlotState state = SimSlotState.getCurrentState(); + boolean isMultiSim = SimSlotState.isMultiSim(); + + assertEquals(2, state.numActiveSlots); + assertEquals(2, state.numActiveSims); + assertEquals(2, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(1, state.numActiveMepSlots); + assertTrue(isMultiSim); + } + + @Test + @SmallTest public void testDsds_physicalAndEsimCardWithProfile() { doReturn(mActiveCard).when(mEsimSlot).getUiccCard(); setupDualSim(mPhysicalSlot, mEsimSlot); @@ -345,6 +420,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(2, state.numActiveSims); assertEquals(1, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertTrue(isMultiSim); } @@ -359,6 +436,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(2, state.numActiveSims); assertEquals(0, state.numActiveEsims); + assertEquals(0, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertTrue(isMultiSim); } @@ -382,6 +461,8 @@ public class SimSlotStateTest extends TelephonyTest { assertEquals(2, state.numActiveSlots); assertEquals(1, state.numActiveSims); assertEquals(1, state.numActiveEsims); + assertEquals(1, state.numActiveEsimSlots); + assertEquals(0, state.numActiveMepSlots); assertFalse(isMultiSim); // one Uicc Port does not have active sim profile } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java index b358b6daa4..1498eb4d49 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.annotation.NonNull; import android.os.Looper; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.NetworkType; @@ -56,6 +57,7 @@ import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.Call; @@ -67,6 +69,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.imsphone.ImsPhoneConnection; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage; @@ -76,6 +79,7 @@ import com.android.internal.telephony.protobuf.nano.MessageNano; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccPort; +import com.android.internal.telephony.uicc.UiccProfile; import com.android.internal.telephony.uicc.UiccSlot; import org.junit.After; @@ -112,12 +116,14 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { private GsmCdmaCall mCsCall1; private ImsPhoneCall mImsCall0; private ImsPhoneCall mImsCall1; + private VonrHelper mVonrHelper; private static class TestableVoiceCallSessionStats extends VoiceCallSessionStats { private long mTimeMillis = 0L; - TestableVoiceCallSessionStats(int phoneId, Phone phone) { - super(phoneId, phone); + TestableVoiceCallSessionStats(int phoneId, Phone phone, + @NonNull FeatureFlags featureFlags) { + super(phoneId, phone, featureFlags); } @Override @@ -158,6 +164,7 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { mCsCall1 = mock(GsmCdmaCall.class); mImsCall0 = mock(ImsPhoneCall.class); mImsCall1 = mock(ImsPhoneCall.class); + mVonrHelper = mock(VonrHelper.class); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mSecondPhone}); doReturn(CARRIER_ID_SLOT_0).when(mPhone).getCarrierId(); // mPhone's mContext/mSST/mServiceState has been set up by TelephonyTest @@ -178,8 +185,13 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { doReturn(true).when(mEsimSlot).isActive(); doReturn(CardState.CARDSTATE_PRESENT).when(mEsimSlot).getCardState(); doReturn(true).when(mEsimSlot).isEuicc(); - doReturn(0).when(mInactivePort).getNumApplications(); - doReturn(4).when(mActivePort).getNumApplications(); + + UiccProfile inactiveProfile = mock(UiccProfile.class); + UiccProfile activeProfile = mock(UiccProfile.class); + doReturn(0).when(inactiveProfile).getNumApplications(); + doReturn(4).when(activeProfile).getNumApplications(); + doReturn(inactiveProfile).when(mInactivePort).getUiccProfile(); + doReturn(activeProfile).when(mActivePort).getUiccProfile(); doReturn(new UiccSlot[] {mPhysicalSlot}).when(mUiccController).getUiccSlots(); doReturn(mPhysicalSlot).when(mUiccController).getUiccSlot(eq(0)); @@ -190,6 +202,7 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { doReturn(PhoneConstants.PHONE_TYPE_IMS).when(mImsConnection0).getPhoneType(); doReturn(false).when(mImsConnection0).isEmergencyCall(); + doReturn(false).when(mImsConnection0).isCrossSimCall(); doReturn(PhoneConstants.PHONE_TYPE_IMS).when(mImsConnection1).getPhoneType(); doReturn(false).when(mImsConnection1).isEmergencyCall(); doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mGsmConnection0).getPhoneType(); @@ -197,14 +210,21 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mGsmConnection1).getPhoneType(); doReturn(false).when(mGsmConnection1).isEmergencyCall(); + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when(mImsPhone) + .getImsRegistrationTech(); + if (Looper.myLooper() == null) { Looper.prepare(); } - mVoiceCallSessionStats0 = new TestableVoiceCallSessionStats(0, mPhone); + doReturn(mVonrHelper).when(mMetricsCollector).getVonrHelper(); + + mVoiceCallSessionStats0 = new TestableVoiceCallSessionStats(0, mPhone, mFeatureFlags); mVoiceCallSessionStats0.onServiceStateChanged(mServiceState); - mVoiceCallSessionStats1 = new TestableVoiceCallSessionStats(1, mSecondPhone); + mVoiceCallSessionStats1 = new TestableVoiceCallSessionStats(1, mSecondPhone, mFeatureFlags); mVoiceCallSessionStats1.onServiceStateChanged(mSecondServiceState); + + doReturn(true).when(mFeatureFlags).vonrEnabledMetric(); } @After @@ -235,7 +255,6 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { ImsReasonInfo.CODE_REMOTE_CALL_DECLINE); expectedCall.setupDurationMillis = 200; expectedCall.setupFailed = true; - expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN; expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB; expectedCall.mainCodecQuality = VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND; @@ -1513,6 +1532,75 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { @Test @SmallTest + public void singleCrossSimCall_moAccepted() { + setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_LTE); + doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).when(mImsPhone) + .getImsRegistrationTech(); + doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech(); + doReturn(false).when(mImsConnection0).isIncoming(); + doReturn(true).when(mImsConnection0).isCrossSimCall(); + doReturn(2000L).when(mImsConnection0).getCreateTime(); + doReturn(1000L).when(mImsConnection0).getDurationMillis(); + doReturn(mImsCall0).when(mImsConnection0).getCall(); + doReturn(new ArrayList(List.of(mImsConnection0))).when(mImsCall0).getConnections(); + VoiceCallSession expectedCall = + makeSlot0CallProto( + VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS, + VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO, + TelephonyManager.NETWORK_TYPE_IWLAN, + ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE); + expectedCall.isIwlanCrossSimAtStart = true; + expectedCall.isIwlanCrossSimAtEnd = true; + expectedCall.isIwlanCrossSimAtConnected = true; + + expectedCall.bandAtEnd = 0; // not configured for IWLAN + expectedCall.setupDurationMillis = 200; + expectedCall.setupFailed = false; + expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB; + expectedCall.mainCodecQuality = + VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND; + expectedCall.disconnectExtraMessage = "normal call clearing"; + expectedCall.callDuration = + VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_LESS_THAN_ONE_MINUTE; + VoiceCallRatUsage expectedRatUsage = + makeRatUsageProto( + CARRIER_ID_SLOT_0, TelephonyManager.NETWORK_TYPE_IWLAN, 2000L, 100000L, 1L); + final AtomicReference<VoiceCallRatUsage[]> ratUsage = setupRatUsageCapture(); + + mVoiceCallSessionStats0.setTimeMillis(2000L); + doReturn(Call.State.DIALING).when(mImsCall0).getState(); + doReturn(Call.State.DIALING).when(mImsConnection0).getState(); + mVoiceCallSessionStats0.onImsDial(mImsConnection0); + mVoiceCallSessionStats0.setTimeMillis(2100L); + mVoiceCallSessionStats0.onAudioCodecChanged( + mImsConnection0, ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB); + mVoiceCallSessionStats0.setTimeMillis(2200L); + doReturn(Call.State.ALERTING).when(mImsCall0).getState(); + doReturn(Call.State.ALERTING).when(mImsConnection0).getState(); + mVoiceCallSessionStats0.onCallStateChanged(mImsCall0); + mVoiceCallSessionStats0.setTimeMillis(12000L); + doReturn(Call.State.ACTIVE).when(mImsCall0).getState(); + doReturn(Call.State.ACTIVE).when(mImsConnection0).getState(); + mVoiceCallSessionStats0.onCallStateChanged(mImsCall0); + mVoiceCallSessionStats0.setTimeMillis(100000L); + mVoiceCallSessionStats0.onImsCallTerminated( + mImsConnection0, + new ImsReasonInfo( + ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, 0, "normal call clearing")); + + ArgumentCaptor<VoiceCallSession> callCaptor = + ArgumentCaptor.forClass(VoiceCallSession.class); + verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture()); + verify(mPersistAtomsStorage, times(1)).addVoiceCallRatUsage(any()); + verifyNoMoreInteractions(mPersistAtomsStorage); + assertProtoEquals(expectedCall, callCaptor.getValue()); + assertThat(ratUsage.get()).hasLength(1); + assertProtoEquals(expectedRatUsage, ratUsage.get()[0]); + } + + @Test + @SmallTest public void singleCsCall_moRejected() { doReturn(false).when(mGsmConnection0).isIncoming(); doReturn(2000L).when(mGsmConnection0).getCreateTime(); @@ -2512,6 +2600,8 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { public void singleWifiCall_preferred() { setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_LTE); doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN).when(mImsPhone) + .getImsRegistrationTech(); doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech(); doReturn(true).when(mImsConnection0).isIncoming(); doReturn(2000L).when(mImsConnection0).getCreateTime(); @@ -2560,6 +2650,8 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { public void singleWifiCall_airPlaneMode() { setServiceStateWithWifiCalling(mServiceState, TelephonyManager.NETWORK_TYPE_UNKNOWN); doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN).when(mImsPhone) + .getImsRegistrationTech(); doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech(); doReturn(true).when(mImsConnection0).isIncoming(); doReturn(2000L).when(mImsConnection0).getCreateTime(); @@ -2603,6 +2695,63 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { assertProtoEquals(expectedRatUsage, ratUsage.get()[0]); } + @Test + @SmallTest + public void singleCall_vonrEnabled() { + setServiceState(mServiceState, TelephonyManager.NETWORK_TYPE_LTE); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsStats).getImsVoiceRadioTech(); + doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(false).when(mImsConnection0).isIncoming(); + doReturn(2000L).when(mImsConnection0).getCreateTime(); + doReturn(0L).when(mImsConnection0).getDurationMillis(); + doReturn(mImsCall0).when(mImsConnection0).getCall(); + doReturn(true).when(mVonrHelper).getVonrEnabled(anyInt()); + doReturn(new ArrayList(List.of(mImsConnection0))).when(mImsCall0).getConnections(); + VoiceCallSession expectedCall = + makeSlot0CallProto( + VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS, + VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO, + TelephonyManager.NETWORK_TYPE_LTE, + ImsReasonInfo.CODE_REMOTE_CALL_DECLINE); + expectedCall.setupDurationMillis = 200; + expectedCall.setupFailed = true; + expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN; + expectedCall.codecBitmask = 1L << AudioCodec.AUDIO_CODEC_EVS_SWB; + expectedCall.mainCodecQuality = + VOICE_CALL_SESSION__MAIN_CODEC_QUALITY__CODEC_QUALITY_SUPER_WIDEBAND; + expectedCall.ratAtConnected = TelephonyManager.NETWORK_TYPE_UNKNOWN; + expectedCall.callDuration = VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_UNKNOWN; + expectedCall.vonrEnabled = true; + VoiceCallRatUsage expectedRatUsage = + makeRatUsageProto( + CARRIER_ID_SLOT_0, TelephonyManager.NETWORK_TYPE_LTE, 2000L, 12000L, 1L); + final AtomicReference<VoiceCallRatUsage[]> ratUsage = setupRatUsageCapture(); + + mVoiceCallSessionStats0.setTimeMillis(2000L); + doReturn(Call.State.DIALING).when(mImsCall0).getState(); + doReturn(Call.State.DIALING).when(mImsConnection0).getState(); + mVoiceCallSessionStats0.onImsDial(mImsConnection0); + mVoiceCallSessionStats0.setTimeMillis(2100L); + mVoiceCallSessionStats0.onAudioCodecChanged( + mImsConnection0, ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB); + mVoiceCallSessionStats0.setTimeMillis(2200L); + doReturn(Call.State.ALERTING).when(mImsCall0).getState(); + doReturn(Call.State.ALERTING).when(mImsConnection0).getState(); + mVoiceCallSessionStats0.onCallStateChanged(mImsCall0); + mVoiceCallSessionStats0.setTimeMillis(12000L); + mVoiceCallSessionStats0.onImsCallTerminated( + mImsConnection0, new ImsReasonInfo(ImsReasonInfo.CODE_REMOTE_CALL_DECLINE, 0)); + + ArgumentCaptor<VoiceCallSession> callCaptor = + ArgumentCaptor.forClass(VoiceCallSession.class); + verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture()); + verify(mPersistAtomsStorage, times(1)).addVoiceCallRatUsage(any()); + verifyNoMoreInteractions(mPersistAtomsStorage); + assertProtoEquals(expectedCall, callCaptor.getValue()); + assertThat(ratUsage.get()).hasLength(1); + assertProtoEquals(expectedRatUsage, ratUsage.get()[0]); + } + private AtomicReference<VoiceCallRatUsage[]> setupRatUsageCapture() { final AtomicReference<VoiceCallRatUsage[]> ratUsage = new AtomicReference<>(null); doAnswer( @@ -2690,6 +2839,7 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { call.isRoaming = false; call.setupBeginMillis = 0L; call.signalStrengthAtEnd = 2; + call.vonrEnabled = false; return call; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java new file mode 100644 index 0000000000..04cd9257c8 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VonrHelperTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.metrics; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; + +import android.annotation.NonNull; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class VonrHelperTest extends TelephonyTest { + private static final int SUBID = 1; + + private static class TestableVonrHelper extends VonrHelper { + TestableVonrHelper(@NonNull FeatureFlags featureFlags) { + super(featureFlags); + } + + @Override + public void updateVonrEnabledState() { + mVonrRunnable.run(); + } + } + + private TestableVonrHelper mVonrHelper; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + doReturn(SUBID).when(mPhone).getSubId(); + doReturn(false).when(mTelephonyManager).isVoNrEnabled(); + mVonrHelper = new TestableVonrHelper(mFeatureFlags); + doReturn(true).when(mFeatureFlags).vonrEnabledMetric(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + @SmallTest + public void vonr_enabled() { + doReturn(true).when(mTelephonyManager).isVoNrEnabled(); + + mVonrHelper.updateVonrEnabledState(); + + assertThat(mVonrHelper.getVonrEnabled(SUBID)).isTrue(); + } + + @Test + @SmallTest + public void vonr_disabled() { + mVonrHelper.updateVonrEnabledState(); + + assertThat(mVonrHelper.getVonrEnabled(SUBID)).isFalse(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/TEST_MAPPING b/tests/telephonytests/src/com/android/internal/telephony/nitz/TEST_MAPPING new file mode 100644 index 0000000000..4063803716 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksTelephonyTests", + "options": [ + { + "include-filter": "com.android.internal.telephony.nitz." + } + ] + } + ] +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java index baa00c156c..76cd4ade6f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java @@ -280,7 +280,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { public void testReportIncomingDatagramCount() { mTestStats.initializeParams(); - int result = SatelliteManager.SATELLITE_ERROR_NONE; + int result = SatelliteManager.SATELLITE_RESULT_SUCCESS; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportIncomingDatagramCount(result); } @@ -303,7 +303,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_SERVER_ERROR; + result = SatelliteManager.SATELLITE_RESULT_SERVER_ERROR; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportIncomingDatagramCount(result); } @@ -326,7 +326,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + result = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportIncomingDatagramCount(result); } @@ -354,7 +354,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { public void testReportProvisionCount() { mTestStats.initializeParams(); - int result = SatelliteManager.SATELLITE_ERROR_NONE; + int result = SatelliteManager.SATELLITE_RESULT_SUCCESS; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportProvisionCount(result); } @@ -377,7 +377,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_SERVER_ERROR; + result = SatelliteManager.SATELLITE_RESULT_SERVER_ERROR; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportProvisionCount(result); } @@ -400,7 +400,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + result = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportProvisionCount(result); } @@ -428,7 +428,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { public void testReportDeprovisionCount() { mTestStats.initializeParams(); - int result = SatelliteManager.SATELLITE_ERROR_NONE; + int result = SatelliteManager.SATELLITE_RESULT_SUCCESS; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportDeprovisionCount(result); } @@ -451,7 +451,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_SERVER_ERROR; + result = SatelliteManager.SATELLITE_RESULT_SERVER_ERROR; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportDeprovisionCount(result); } @@ -474,7 +474,7 @@ public class ControllerMetricsStatsTest extends TelephonyTest { assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); mTestStats.initializeParams(); - result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + result = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; for (int i = 0; i < 10; i++) { mControllerMetricsStatsUT.reportDeprovisionCount(result); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index bc1d7674ad..fd5f6ab2d1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -20,26 +20,39 @@ import static com.android.internal.telephony.satellite.DatagramController.SATELL import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; import android.os.Looper; import android.os.Message; +import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.R; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; @@ -53,8 +66,12 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -73,12 +90,29 @@ public class DatagramDispatcherTest extends TelephonyTest { @Mock private DatagramReceiver mMockDatagramReceiver; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private ControllerMetricsStats mMockControllerMetricsStats; + @Mock private SatelliteSessionController mMockSatelliteSessionController; /** Variables required to send datagram in the unit tests. */ LinkedBlockingQueue<Integer> mResultListener; SatelliteDatagram mDatagram; InOrder mInOrder; + private static final long TIMEOUT = 500; + private List<Integer> mIntegerConsumerResult = new ArrayList<>(); + private Semaphore mIntegerConsumerSemaphore = new Semaphore(0); + private Consumer<Integer> mIntegerConsumer = integer -> { + logd("mIntegerConsumer: integer=" + integer); + mIntegerConsumerResult.add(integer); + try { + mIntegerConsumerSemaphore.release(); + } catch (Exception ex) { + loge("mIntegerConsumer: Got exception in releasing semaphore, ex=" + ex); + } + }; + + private final int mConfigSendSatelliteDatagramToModemInDemoMode = + R.bool.config_send_satellite_datagram_to_modem_in_demo_mode; + @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); @@ -93,7 +127,10 @@ public class DatagramDispatcherTest extends TelephonyTest { mMockSatelliteModemInterface); replaceInstance(ControllerMetricsStats.class, "sInstance", null, mMockControllerMetricsStats); + replaceInstance(SatelliteSessionController.class, "sInstance", null, + mMockSatelliteSessionController); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(), mMockDatagramController); mTestDemoModeDatagramDispatcher = new TestDatagramDispatcher(mContext, Looper.myLooper(), @@ -119,7 +156,6 @@ public class DatagramDispatcherTest extends TelephonyTest { @Test public void testSendSatelliteDatagram_usingSatelliteModemInterface_success() throws Exception { - doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[3]; @@ -129,188 +165,158 @@ public class DatagramDispatcherTest extends TelephonyTest { return null; }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class)); + doReturn(true).when(mMockDatagramController) + .needsWaitingForSatelliteConnected(); + when(mMockDatagramController.getDatagramWaitTimeForConnectedState()) + .thenReturn(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT); + mResultListener.clear(); mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, true, mResultListener::offer); + processAllMessages(); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(1), + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState(); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); processAllMessages(); mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); verifyNoMoreInteractions(mMockDatagramController); + verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram( + any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class)); + assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); - } + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); - @Test - public void testSendSatelliteDatagram_usingSatelliteModemInterface_failure() throws Exception { - doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[3]; + clearInvocations(mMockSatelliteModemInterface); + clearInvocations(mMockDatagramController); + mResultListener.clear(); - mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, - new AsyncResult(message.obj, null, - new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_SERVICE_ERROR))) - .sendToTarget(); - return null; - }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), - anyBoolean(), anyBoolean(), any(Message.class)); - - mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, + clearInvocations(mMockSatelliteModemInterface); + clearInvocations(mMockDatagramController); + mResultListener.clear(); + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, true, mResultListener::offer); - processAllMessages(); + verifyZeroInteractions(mMockSatelliteModemInterface); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState(); + assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); - mInOrder.verify(mMockDatagramController).isPollingInIdleState(); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + moveTimeForward(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT); + processAllMessages(); + verifyZeroInteractions(mMockSatelliteModemInterface); mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), - eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1), + eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE)); mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), + .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - verifyNoMoreInteractions(mMockDatagramController); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + assertEquals(1, mResultListener.size()); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); - } - - @Test - public void testSendSatelliteDatagram_usingCommandsInterface_phoneNull() throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null}); + mResultListener.clear(); + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertEquals(0, mResultListener.size()); + clearInvocations(mMockSatelliteModemInterface); + clearInvocations(mMockDatagramController); + mResultListener.clear(); mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, true, mResultListener::offer); - processAllMessages(); + verifyZeroInteractions(mMockSatelliteModemInterface); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState(); + assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); + assertEquals(0, mResultListener.size()); - mInOrder.verify(mMockDatagramController).isPollingInIdleState(); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), - eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - verifyNoMoreInteractions(mMockDatagramController); - - assertThat(mResultListener.peek()) - .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } - - @Test - public void testSendSatelliteDatagram_usingCommandsInterface_success() throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - - mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, - new AsyncResult(message.obj, null, null)) - .sendToTarget(); - return null; - }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), - anyBoolean()); - - mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, - true, mResultListener::offer); - + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); processAllMessages(); - - mInOrder.verify(mMockDatagramController).isPollingInIdleState(); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - mInOrder.verify(mMockDatagramController) - .updateSendStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - verifyNoMoreInteractions(mMockDatagramController); - - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertEquals(1, mResultListener.size()); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED); + assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted()); } @Test - public void testSendSatelliteDatagram_usingCommandsInterface_failure() throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + public void testSendSatelliteDatagram_usingSatelliteModemInterface_failure() throws Exception { doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; + Message message = (Message) invocation.getArguments()[3]; mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, new AsyncResult(message.obj, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_SERVICE_ERROR))) + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR))) .sendToTarget(); return null; - }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), - anyBoolean()); + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); - mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, true, mResultListener::offer); processAllMessages(); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), - eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); verifyNoMoreInteractions(mMockDatagramController); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } @Test public void testSendSatelliteDatagram_DemoMode_Align_Success() throws Exception { - mTestDemoModeDatagramDispatcher.setDemoMode(true); - mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(true); - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - - mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + Message message = (Message) invocation.getArguments()[3]; + mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, new AsyncResult(message.obj, null, null)) .sendToTarget(); return null; - }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), - anyBoolean()); + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true); mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, true, mResultListener::offer); @@ -320,38 +326,35 @@ public class DatagramDispatcherTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); mTestDemoModeDatagramDispatcher.setDemoMode(false); - mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false); } @Test public void testSendSatelliteDatagram_DemoMode_Align_failed() throws Exception { - long previousTimer = mTestDemoModeDatagramDispatcher.getSatelliteAlignedTimeoutDuration(); - mTestDemoModeDatagramDispatcher.setDemoMode(true); - mTestDemoModeDatagramDispatcher.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN); - mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); - - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - + Message message = (Message) invocation.getArguments()[3]; mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, new AsyncResult(message.obj, null, null)) .sendToTarget(); return null; - }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), - anyBoolean()); + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + + long previousTimer = mTestDemoModeDatagramDispatcher.getSatelliteAlignedTimeoutDuration(); + mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false); mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, true, mResultListener::offer); @@ -359,36 +362,36 @@ public class DatagramDispatcherTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); processAllFutureMessages(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), - anyInt(), eq(SatelliteManager.SATELLITE_NOT_REACHABLE)); + anyInt(), eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_NOT_REACHABLE); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); mTestDemoModeDatagramDispatcher.setDemoMode(false); - mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false); mTestDemoModeDatagramDispatcher.setDuration(previousTimer); } @Test public void testSendSatelliteDatagram_DemoMode_data_type_location_sharing() throws Exception { - mTestDemoModeDatagramDispatcher.setDemoMode(true); - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - + Message message = (Message) invocation.getArguments()[3]; mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, - new AsyncResult(message.obj, null, null)) - .sendToTarget(); + new AsyncResult(message.obj, SatelliteManager.SATELLITE_RESULT_SUCCESS, + null)).sendToTarget(); return null; - }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), - anyBoolean()); + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, true, mResultListener::offer); @@ -398,22 +401,22 @@ public class DatagramDispatcherTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mTestDemoModeDatagramDispatcher.setDemoMode(false); - mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false); } @Test @@ -424,7 +427,8 @@ public class DatagramDispatcherTest extends TelephonyTest { true, mResultListener::offer); processAllMessages(); // As modem is busy receiving datagrams, sending datagram did not proceed further. - mInOrder.verify(mMockDatagramController).isPollingInIdleState(); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController, times(2)).isPollingInIdleState(); verifyNoMoreInteractions(mMockDatagramController); } @@ -449,11 +453,11 @@ public class DatagramDispatcherTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateSendStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), - eq(1), eq(SatelliteManager.SATELLITE_REQUEST_ABORTED)); + eq(1), eq(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED)); mInOrder.verify(mMockDatagramController) .updateSendStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); } @Test @@ -466,7 +470,83 @@ public class DatagramDispatcherTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateSendStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + } + + @Test + public void testSendSatelliteDatagramToModemInDemoMode() + throws Exception { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[3]; + mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true); + mIntegerConsumerSemaphore.drainPermits(); + + // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is true + mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null); + mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, true); + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mIntegerConsumer); + processAllMessages(); + waitForIntegerConsumerResult(1); + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, + (int) mIntegerConsumerResult.get(0)); + mIntegerConsumerResult.clear(); + verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram( + any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class)); + + // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is false + reset(mMockSatelliteModemInterface); + mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null); + mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, false); + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mIntegerConsumer); + processAllMessages(); + waitForIntegerConsumerResult(1); + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, + (int) mIntegerConsumerResult.get(0)); + mIntegerConsumerResult.clear(); + verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram( + any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class)); + + // Send datagram one more time + reset(mMockSatelliteModemInterface); + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mIntegerConsumer); + processAllMessages(); + waitForIntegerConsumerResult(1); + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, + (int) mIntegerConsumerResult.get(0)); + mIntegerConsumerResult.clear(); + verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram( + any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class)); + + mTestDemoModeDatagramDispatcher.setDemoMode(false); + mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null); + } + + private boolean waitForIntegerConsumerResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIntegerConsumerSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive IIntegerConsumer() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForIIntegerConsumerResult: Got exception=" + ex); + return false; + } + } + return true; } private static class TestDatagramDispatcher extends DatagramDispatcher { @@ -483,8 +563,8 @@ public class DatagramDispatcherTest extends TelephonyTest { } @Override - protected void onDeviceAlignedWithSatellite(boolean isAligned) { - super.onDeviceAlignedWithSatellite(isAligned); + protected void setDeviceAlignedWithSatellite(boolean isAligned) { + super.setDeviceAlignedWithSatellite(isAligned); } @Override @@ -492,8 +572,18 @@ public class DatagramDispatcherTest extends TelephonyTest { return mLong; } + @Override + protected void setShouldSendDatagramToModemInDemoMode( + @Nullable Boolean shouldSendToModemInDemoMode) { + super.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode); + } + public void setDuration(long duration) { mLong = duration; } } + + private static void loge(String message) { + Rlog.e(TAG, message); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index 1c3777dc30..0e16e25894 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -18,19 +18,16 @@ package com.android.internal.telephony.satellite; import static com.android.internal.telephony.satellite.DatagramController.SATELLITE_ALIGN_TIMEOUT; -import android.annotation.NonNull; -import android.content.Context; -import android.provider.Telephony; -import android.telephony.satellite.ISatelliteDatagramCallback; -import android.test.mock.MockContentResolver; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; @@ -38,20 +35,27 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; import android.os.AsyncResult; +import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.IBinder; import android.os.RemoteException; +import android.provider.Telephony; +import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; +import android.test.mock.MockContentResolver; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.util.Pair; import com.android.internal.telephony.IVoidConsumer; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; @@ -64,6 +68,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @@ -82,6 +87,7 @@ public class DatagramReceiverTest extends TelephonyTest { @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private ControllerMetricsStats mMockControllerMetricsStats; + @Mock private SatelliteSessionController mMockSatelliteSessionController; /** Variables required to receive datagrams in the unit tests. */ LinkedBlockingQueue<Integer> mResultListener; @@ -110,6 +116,8 @@ public class DatagramReceiverTest extends TelephonyTest { mMockSatelliteModemInterface); replaceInstance(ControllerMetricsStats.class, "sInstance", null, mMockControllerMetricsStats); + replaceInstance(SatelliteSessionController.class, "sInstance", null, + mMockSatelliteSessionController); mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(), mMockDatagramController); @@ -124,6 +132,7 @@ public class DatagramReceiverTest extends TelephonyTest { when(mMockDatagramController.isSendingInIdleState()).thenReturn(true); when(mMockDatagramController.isPollingInIdleState()).thenReturn(true); + when(mMockDatagramController.needsWaitingForSatelliteConnected()).thenReturn(false); processAllMessages(); } @@ -152,118 +161,82 @@ public class DatagramReceiverTest extends TelephonyTest { .sendToTarget(); return null; }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class)); + doReturn(true).when(mMockDatagramController).needsWaitingForSatelliteConnected(); + when(mMockDatagramController.getDatagramWaitTimeForConnectedState()) + .thenReturn(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT); + mResultListener.clear(); mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); - processAllMessages(); - - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); - } - - @Test - public void testPollPendingSatelliteDatagrams_usingSatelliteModemInterface_failure() - throws Exception { - doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - - mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, - new AsyncResult(message.obj, null, - new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_SERVICE_ERROR))) - .sendToTarget(); - return null; - }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class)); - - mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); - + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(0), + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState(); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertTrue(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted()); + + doReturn(false).when(mMockDatagramController).needsWaitingForSatelliteConnected(); + mDatagramReceiverUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); processAllMessages(); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), - eq(0), eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); - - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); - } - - @Test - public void testPollPendingSatelliteDatagrams_usingCommandsInterface_phoneNull() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null}); - + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + verify(mMockSatelliteModemInterface, times(1)) + .pollPendingSatelliteDatagrams(any(Message.class)); + assertEquals(1, mResultListener.size()); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); + assertFalse(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted()); + + clearInvocations(mMockSatelliteModemInterface); + mResultListener.clear(); + doReturn(true).when(mMockDatagramController).needsWaitingForSatelliteConnected(); mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); - processAllMessages(); + mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected(); + mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState(); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertTrue(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted()); - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), - eq(0), eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); - - assertThat(mResultListener.peek()) - .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } - - @Test - public void testPollPendingSatelliteDatagrams_usingCommandsInterface_success() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - - mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, - new AsyncResult(message.obj, null, null)) - .sendToTarget(); - return null; - }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class)); - - mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); - + moveTimeForward(DatagramController.DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMEOUT); processAllMessages(); - - mInOrder.verify(mMockDatagramController) - .updateReceiveStatus(eq(SUB_ID), - eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); - - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), eq(0), + eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE)); + mInOrder.verify(mMockDatagramController).updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertEquals(1, mResultListener.size()); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); + assertFalse(mDatagramReceiverUT.isDatagramWaitForConnectedStateTimerStarted()); + + mResultListener.clear(); + mDatagramReceiverUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + verifyZeroInteractions(mMockSatelliteModemInterface); + assertEquals(0, mResultListener.size()); } @Test - public void testPollPendingSatelliteDatagrams_usingCommandsInterface_failure() + public void testPollPendingSatelliteDatagrams_usingSatelliteModemInterface_failure() throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, new AsyncResult(message.obj, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_SERVICE_ERROR))) + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR))) .sendToTarget(); return null; - }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class)); + }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class)); mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); @@ -272,13 +245,14 @@ public class DatagramReceiverTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), - eq(0), eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR)); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + assertThat(mResultListener.peek()).isEqualTo( + SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR); } @Test @@ -292,29 +266,40 @@ public class DatagramReceiverTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); } @Test public void testSatelliteDatagramReceived_success_zeroPendingCount() { + TestSatelliteDatagramCallback testSatelliteDatagramCallback = + new TestSatelliteDatagramCallback(); + + mSatelliteDatagramListenerHandler.addListener(testSatelliteDatagramCallback); mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/, new AsyncResult(null, new Pair<>(mDatagram, 0), null)) .sendToTarget(); - processAllMessages(); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); + assertTrue(testSatelliteDatagramCallback.waitForOnSatelliteDatagramReceived()); + + assertTrue(testSatelliteDatagramCallback.sendInternalAck()); + try { + processAllFutureMessages(); + } catch (Exception e) { + fail("Unexpected exception e=" + e); + } } @Test @@ -328,14 +313,14 @@ public class DatagramReceiverTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS), - eq(10), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(10), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); } @Test public void testPollPendingSatelliteDatagrams_DemoMode_Align_succeed() throws Exception { // Checks invalid case only as SatelliteController does not exist in unit test mTestDemoModeDatagramReceiver.setDemoMode(true); - mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(true); + mTestDemoModeDatagramReceiver.setDeviceAlignedWithSatellite(true); when(mMockDatagramController.getDemoModeDatagram()).thenReturn(mDatagram); mTestDemoModeDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); processAllMessages(); @@ -344,19 +329,19 @@ public class DatagramReceiverTest extends TelephonyTest { .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), anyInt(), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), anyInt(), - eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + eq(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE)); verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), anyInt(), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); assertThat(mResultListener.peek()) - .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + .isEqualTo(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE); } @Test @@ -365,7 +350,7 @@ public class DatagramReceiverTest extends TelephonyTest { long previousTimer = mTestDemoModeDatagramReceiver.getSatelliteAlignedTimeoutDuration(); mTestDemoModeDatagramReceiver.setDemoMode(true); mTestDemoModeDatagramReceiver.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN); - mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramReceiver.setDeviceAlignedWithSatellite(false); when(mMockDatagramController.getDemoModeDatagram()).thenReturn(mDatagram); mTestDemoModeDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); processAllMessages(); @@ -374,23 +359,23 @@ public class DatagramReceiverTest extends TelephonyTest { .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), anyInt(), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); processAllFutureMessages(); verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), anyInt(), - eq(SatelliteManager.SATELLITE_NOT_REACHABLE)); + eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE)); verify(mMockDatagramController) .updateReceiveStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), anyInt(), - eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); assertThat(mResultListener.peek()) - .isEqualTo(SatelliteManager.SATELLITE_NOT_REACHABLE); + .isEqualTo(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE); mTestDemoModeDatagramReceiver.setDemoMode(false); - mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramReceiver.setDeviceAlignedWithSatellite(false); mTestDemoModeDatagramReceiver.setDuration(previousTimer); } @@ -400,7 +385,7 @@ public class DatagramReceiverTest extends TelephonyTest { mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); processAllMessages(); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_MODEM_BUSY); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); } @Test @@ -410,7 +395,7 @@ public class DatagramReceiverTest extends TelephonyTest { mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); processAllMessages(); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_MODEM_BUSY); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_MODEM_BUSY); } @Test @@ -434,11 +419,11 @@ public class DatagramReceiverTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateReceiveStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), - eq(10), eq(SatelliteManager.SATELLITE_REQUEST_ABORTED)); + eq(10), eq(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED)); mInOrder.verify(mMockDatagramController) .updateReceiveStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); } @Test @@ -453,12 +438,12 @@ public class DatagramReceiverTest extends TelephonyTest { mInOrder.verify(mMockDatagramController) .updateReceiveStatus(anyInt(), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), - eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS)); } @Test public void testRegisterForSatelliteDatagram_satelliteNotSupported() { - when(mMockSatelliteController.isSatelliteSupported()).thenReturn(false); + when(mMockSatelliteController.isSatelliteSupportedViaOem()).thenReturn(false); ISatelliteDatagramCallback callback = new ISatelliteDatagramCallback() { @Override @@ -474,7 +459,7 @@ public class DatagramReceiverTest extends TelephonyTest { }; assertThat(mDatagramReceiverUT.registerForSatelliteDatagram(SUB_ID, callback)) - .isEqualTo(SatelliteManager.SATELLITE_NOT_SUPPORTED); + .isEqualTo(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED); } private static class TestDatagramReceiver extends DatagramReceiver { @@ -491,8 +476,8 @@ public class DatagramReceiverTest extends TelephonyTest { } @Override - protected void onDeviceAlignedWithSatellite(boolean isAligned) { - super.onDeviceAlignedWithSatellite(isAligned); + protected void setDeviceAlignedWithSatellite(boolean isAligned) { + super.setDeviceAlignedWithSatellite(isAligned); } @Override @@ -504,4 +489,57 @@ public class DatagramReceiverTest extends TelephonyTest { mLong = duration; } } + + private static class TestSatelliteDatagramCallback extends ISatelliteDatagramCallback.Stub { + @Nullable private IVoidConsumer mInternalAck; + private final Semaphore mSemaphore = new Semaphore(0); + + @Override + public void onSatelliteDatagramReceived(long datagramId, + @NonNull SatelliteDatagram datagram, int pendingCount, + @NonNull IVoidConsumer internalAck) { + logd("onSatelliteDatagramReceived"); + mInternalAck = internalAck; + try { + internalAck.accept(); + } catch (RemoteException e) { + logd("onSatelliteDatagramReceived: accept e=" + e); + return; + } + + try { + mSemaphore.release(); + } catch (Exception e) { + logd("onSatelliteDatagramReceived: release e=" + e); + } + } + + public boolean waitForOnSatelliteDatagramReceived() { + logd("waitForOnSatelliteDatagramReceived"); + try { + if (!mSemaphore.tryAcquire(1000, TimeUnit.MILLISECONDS)) { + logd("Timed out to receive onSatelliteDatagramReceived"); + return false; + } + } catch (InterruptedException e) { + logd("waitForOnSatelliteDatagramReceived: e=" + e); + return false; + } + return true; + } + + public boolean sendInternalAck() { + if (mInternalAck == null) { + logd("sendInternalAck: mInternalAck is null"); + return false; + } + try { + mInternalAck.accept(); + } catch (RemoteException e) { + logd("sendInternalAck: accept e=" + e); + return false; + } + return true; + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java index c202f0cf00..0944c6c6c6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import android.annotation.NonNull; @@ -75,7 +76,7 @@ public class NtnCapabilityResolverTest extends TelephonyTest { replaceInstance(SatelliteController.class, "sInstance", null, mMockSatelliteController); doReturn(Arrays.asList(SATELLITE_PLMN_ARRAY)) - .when(mMockSatelliteController).getSatellitePlmnList(); + .when(mMockSatelliteController).getSatellitePlmnList(anyInt()); doReturn(mSatelliteSupportedServiceList).when(mMockSatelliteController) .getSupportedSatelliteServices(SUB_ID, SATELLITE_PLMN); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java index 4587b7cfa9..3917a32d52 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java @@ -16,10 +16,7 @@ package com.android.internal.telephony.satellite; -import android.os.Bundle; -import android.os.Handler; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE; import static com.google.common.truth.Truth.assertThat; @@ -27,20 +24,27 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Intent; +import android.content.pm.PackageManager; import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; import android.os.Message; import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.SatelliteManager.SatelliteException; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; import android.util.Log; import com.android.internal.R; @@ -75,9 +79,11 @@ public class PointingAppControllerTest extends TelephonyTest { private PointingAppController mPointingAppController; InOrder mInOrder; + InOrder mInOrderForPointingUi; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private SatelliteController mMockSatelliteController; + @Mock private PackageManager mPackageManager; private TestSatelliteTransmissionUpdateCallback mSatelliteTransmissionUpdateCallback; private TestSatelliteControllerHandler mTestSatelliteControllerHandler; @@ -92,7 +98,7 @@ public class PointingAppControllerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); logd(TAG + " Setup!"); - + mInOrderForPointingUi = inOrder(mContext); replaceInstance(SatelliteModemInterface.class, "sInstance", null, mMockSatelliteModemInterface); replaceInstance(SatelliteController.class, "sInstance", null, @@ -111,7 +117,7 @@ public class PointingAppControllerTest extends TelephonyTest { public void tearDown() throws Exception { logd(TAG + " tearDown"); mResultListener = null; - + mInOrderForPointingUi = null; mSatelliteTransmissionUpdateCallback = null; super.tearDown(); } @@ -237,170 +243,64 @@ public class PointingAppControllerTest extends TelephonyTest { } private void setUpResponseForStartTransmissionUpdates( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SatelliteManager.SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, null, exception); message.sendToTarget(); return null; - }).when(mPhone).startSatellitePositionUpdates(any(Message.class)); - - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - AsyncResult.forMessage(message, null, exception); - message.sendToTarget(); - return null; }).when(mMockSatelliteModemInterface).startSendingSatellitePointingInfo(any(Message.class)); } private void setUpResponseForStopTransmissionUpdates( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SatelliteManager.SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, null, exception); message.sendToTarget(); return null; - }).when(mPhone).stopSatellitePositionUpdates(any(Message.class)); - - doAnswer(invocation -> { - Message message = (Message) invocation.getArguments()[0]; - AsyncResult.forMessage(message, null, exception); - message.sendToTarget(); - return null; }).when(mMockSatelliteModemInterface).stopSendingSatellitePointingInfo(any(Message.class)); } @Test - public void testStartSatelliteTransmissionUpdates_CommandInterface() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - Message testMessage = mTestSatelliteControllerHandler - .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - setUpResponseForStartTransmissionUpdates(SatelliteManager.SATELLITE_ERROR_NONE); - mPointingAppController.startSatelliteTransmissionUpdates(testMessage, mPhone); - - processAllMessages(); - - verify(mMockSatelliteModemInterface, never()) - .startSendingSatellitePointingInfo(eq(testMessage)); - - verify(mPhone) - .startSatellitePositionUpdates(eq(testMessage)); - - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, mResultCode); - - assertTrue(mPointingAppController.getStartedSatelliteTransmissionUpdates()); - } - - @Test public void testStartSatelliteTransmissionUpdates_success() throws Exception { - doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); mPointingAppController.setStartedSatelliteTransmissionUpdates(false); Message testMessage = mTestSatelliteControllerHandler .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - setUpResponseForStartTransmissionUpdates(SatelliteManager.SATELLITE_ERROR_NONE); - mPointingAppController.startSatelliteTransmissionUpdates(testMessage, mPhone); + setUpResponseForStartTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS); + mPointingAppController.startSatelliteTransmissionUpdates(testMessage); verify(mMockSatelliteModemInterface) .startSendingSatellitePointingInfo(eq(testMessage)); - verify(mPhone, never()) - .startSatellitePositionUpdates(eq(testMessage)); - processAllMessages(); assertTrue(mPointingAppController.getStartedSatelliteTransmissionUpdates()); - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, mResultCode); - } - - @Test - public void testStartSatelliteTransmissionUpdates_phoneNull() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - mPointingAppController.setStartedSatelliteTransmissionUpdates(false); - Message testMessage = mTestSatelliteControllerHandler - .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - - mPointingAppController.startSatelliteTransmissionUpdates(testMessage, null); - processAllMessages(); - verify(mMockSatelliteModemInterface, never()) - .startSendingSatellitePointingInfo(eq(testMessage)); - - verify(mPhone, never()) - .startSatellitePositionUpdates(eq(testMessage)); - - assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates()); - - assertEquals(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, mResultCode); - } - - @Test - public void testStopSatelliteTransmissionUpdates_CommandInterface() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - setUpResponseForStopTransmissionUpdates(SatelliteManager.SATELLITE_ERROR_NONE); - Message testMessage = mTestSatelliteControllerHandler - .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, mPhone); - - processAllMessages(); - - verify(mMockSatelliteModemInterface, never()) - .stopSendingSatellitePointingInfo(eq(testMessage)); - - verify(mPhone) - .stopSatellitePositionUpdates(eq(testMessage)); - - assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates()); - - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, mResultCode); + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mResultCode); } @Test public void testStopSatelliteTransmissionUpdates_success() throws Exception { doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - setUpResponseForStopTransmissionUpdates(SatelliteManager.SATELLITE_ERROR_NONE); + setUpResponseForStopTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS); Message testMessage = mTestSatelliteControllerHandler .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, mPhone); + mPointingAppController.stopSatelliteTransmissionUpdates(testMessage); processAllMessages(); verify(mMockSatelliteModemInterface) .stopSendingSatellitePointingInfo(eq(testMessage)); - verify(mPhone, never()) - .stopSatellitePositionUpdates(eq(testMessage)); - assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates()); - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, mResultCode); - } - - @Test - public void testStopSatellitePointingInfo_phoneNull() - throws Exception { - doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); - Message testMessage = mTestSatelliteControllerHandler - .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null); - mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, null); - - processAllMessages(); - - verify(mMockSatelliteModemInterface, never()) - .stopSendingSatellitePointingInfo(eq(testMessage)); - - verify(mPhone, never()) - .stopSatellitePositionUpdates(eq(testMessage)); - - assertEquals(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, mResultCode); - + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mResultCode); } @Test @@ -417,92 +317,67 @@ public class PointingAppControllerTest extends TelephonyTest { } @Test + public void testRestartPointingUi() throws Exception { + mPointingAppController.startPointingUI(true); + mInOrderForPointingUi.verify(mContext).startActivity(any(Intent.class)); + testRestartPointingUi(true); + mPointingAppController.startPointingUI(false); + mInOrderForPointingUi.verify(mContext).startActivity(any(Intent.class)); + testRestartPointingUi(false); + } + + private void testRestartPointingUi(boolean expectedFullScreen) { + when(mContext.getPackageManager()).thenReturn(mPackageManager); + doReturn(new String[]{KEY_POINTING_UI_PACKAGE_NAME}).when(mPackageManager) + .getPackagesForUid(anyInt()); + mPointingAppController.mUidImportanceListener.onUidImportance(1, IMPORTANCE_GONE); + ArgumentCaptor<Intent> restartedIntentCaptor = ArgumentCaptor.forClass(Intent.class); + mInOrderForPointingUi.verify(mContext).startActivity(restartedIntentCaptor.capture()); + Intent restartIntent = restartedIntentCaptor.getValue(); + assertEquals(KEY_POINTING_UI_PACKAGE_NAME, restartIntent.getComponent().getPackageName()); + assertEquals(KEY_POINTING_UI_CLASS_NAME, restartIntent.getComponent().getClassName()); + Bundle b = restartIntent.getExtras(); + assertTrue(b.containsKey(KEY_NEED_FULL_SCREEN)); + // Checking if last value of KEY_NEED_FULL_SCREEN is taken or not + assertEquals(expectedFullScreen, b.getBoolean(KEY_NEED_FULL_SCREEN)); + } + + @Test public void testUpdateSendDatagramTransferState() throws Exception { mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID, - mSatelliteTransmissionUpdateCallback, mPhone); + mSatelliteTransmissionUpdateCallback); mPointingAppController.updateSendDatagramTransferState(SUB_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, 1, - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); assertTrue(waitForSendDatagramStateChangedRessult(1)); assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, mSatelliteTransmissionUpdateCallback.getState()); assertEquals(1, mSatelliteTransmissionUpdateCallback.getSendPendingCount()); - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mSatelliteTransmissionUpdateCallback.getErrorCode()); assertTrue(mSatelliteTransmissionUpdateCallback.inSendDatagramStateCallback); mPointingAppController.unregisterForSatelliteTransmissionUpdates(SUB_ID, - mResultListener::offer, mSatelliteTransmissionUpdateCallback, mPhone); + mResultListener::offer, mSatelliteTransmissionUpdateCallback); mResultListener.clear(); } @Test public void testUpdateReceiveDatagramTransferState() throws Exception { mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID, - mSatelliteTransmissionUpdateCallback, mPhone); + mSatelliteTransmissionUpdateCallback); mPointingAppController.updateReceiveDatagramTransferState(SUB_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, 2, - SatelliteManager.SATELLITE_ERROR_NONE); + SatelliteManager.SATELLITE_RESULT_SUCCESS); assertTrue(waitForReceiveDatagramStateChangedRessult(1)); assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, mSatelliteTransmissionUpdateCallback.getState()); assertEquals(2, mSatelliteTransmissionUpdateCallback.getReceivePendingCount()); - assertEquals(SatelliteManager.SATELLITE_ERROR_NONE, + assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mSatelliteTransmissionUpdateCallback.getErrorCode()); assertTrue(mSatelliteTransmissionUpdateCallback.inReceiveDatagramStateCallback); mPointingAppController.unregisterForSatelliteTransmissionUpdates(SUB_ID, - mResultListener::offer, mSatelliteTransmissionUpdateCallback, mPhone); - mResultListener.clear(); - } - - @Test - public void testRegisterForSatelliteTransmissionUpdates_CommandInterface() throws Exception { + mResultListener::offer, mSatelliteTransmissionUpdateCallback); mResultListener.clear(); - mInOrder = inOrder(mPhone); - TestSatelliteTransmissionUpdateCallback callback1 = new - TestSatelliteTransmissionUpdateCallback(); - TestSatelliteTransmissionUpdateCallback callback2 = new - TestSatelliteTransmissionUpdateCallback(); - int subId1 = 1; - int subId2 = 2; - mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, - callback1, mPhone); - mInOrder.verify(mPhone).registerForSatellitePositionInfoChanged(any(), - eq(1), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, - callback2, mPhone); - mInOrder.verify(mPhone, never()).registerForSatellitePositionInfoChanged(any(), - eq(1), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, - callback1, mPhone); - mInOrder.verify(mPhone).registerForSatellitePositionInfoChanged(any(), - eq(1), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, - callback2, mPhone); - mInOrder.verify(mPhone, never()).registerForSatellitePositionInfoChanged(any(), - eq(1), eq(null)); - mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1, - mResultListener::offer, callback1, mPhone); - processAllMessages(); - //since there are 2 callbacks registered for this sub_id, Handler is not unregistered - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); - mResultListener.remove(); - mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1, - mResultListener::offer, callback2, mPhone); - mInOrder.verify(mPhone).unregisterForSatellitePositionInfoChanged(any(Handler.class)); - mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2, - mResultListener::offer, callback1, mPhone); - processAllMessages(); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); - mResultListener.remove(); - mInOrder.verify(mPhone, never()).unregisterForSatellitePositionInfoChanged( - any(Handler.class)); - mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2, - mResultListener::offer, callback2, null); - processAllMessages(); - assertThat(mResultListener.peek()) - .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - mResultListener.remove(); - mInOrder = null; } @Test @@ -516,53 +391,49 @@ public class PointingAppControllerTest extends TelephonyTest { TestSatelliteTransmissionUpdateCallback(); int subId1 = 3; int subId2 = 4; - mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, - callback1, mPhone); + mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, callback1); mInOrder.verify(mMockSatelliteModemInterface).registerForSatellitePositionInfoChanged(any(), eq(1), eq(null)); mInOrder.verify(mMockSatelliteModemInterface).registerForDatagramTransferStateChanged(any(), eq(4), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, - callback2, mPhone); + mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, callback2); mInOrder.verify(mMockSatelliteModemInterface, never()) .registerForSatellitePositionInfoChanged(any(), eq(1), eq(null)); mInOrder.verify(mMockSatelliteModemInterface, never()) .registerForDatagramTransferStateChanged(any(), eq(4), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, - callback1, mPhone); + mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, callback1); mInOrder.verify(mMockSatelliteModemInterface).registerForSatellitePositionInfoChanged(any(), eq(1), eq(null)); mInOrder.verify(mMockSatelliteModemInterface).registerForDatagramTransferStateChanged(any(), eq(4), eq(null)); - mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, - callback2, mPhone); + mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, callback2); mInOrder.verify(mMockSatelliteModemInterface, never()) .registerForSatellitePositionInfoChanged(any(), eq(1), eq(null)); mInOrder.verify(mMockSatelliteModemInterface, never()) .registerForDatagramTransferStateChanged(any(), eq(4), eq(null)); mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1, - mResultListener::offer, callback1, mPhone); + mResultListener::offer, callback1); processAllMessages(); //since there are 2 callbacks registered for this sub_id, Handler is not unregistered - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); mResultListener.remove(); mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1, - mResultListener::offer, callback2, mPhone); + mResultListener::offer, callback2); mInOrder.verify(mMockSatelliteModemInterface).unregisterForSatellitePositionInfoChanged( any(Handler.class)); mInOrder.verify(mMockSatelliteModemInterface).unregisterForDatagramTransferStateChanged( any(Handler.class)); mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2, - mResultListener::offer, callback1, mPhone); + mResultListener::offer, callback1); processAllMessages(); - assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS); mResultListener.remove(); mInOrder.verify(mMockSatelliteModemInterface, never()) .unregisterForSatellitePositionInfoChanged(any(Handler.class)); mInOrder.verify(mMockSatelliteModemInterface, never()) .unregisterForDatagramTransferStateChanged(any(Handler.class)); mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2, - mResultListener::offer, callback2, null); + mResultListener::offer, callback2); processAllMessages(); mInOrder.verify(mMockSatelliteModemInterface).unregisterForSatellitePositionInfoChanged( any(Handler.class)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java index edfd6105ad..55532ccd39 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java @@ -16,7 +16,14 @@ package com.android.internal.telephony.satellite; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT; +import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GOOD; +import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GREAT; +import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE; +import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_POOR; import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED; +import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_CAPABILITIES; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ENABLED; @@ -24,22 +31,28 @@ import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_NEXT_VI import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED; import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN; +import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN; import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN; import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY; -import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR; -import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE; -import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_ARGUMENTS; -import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_MODEM_STATE; -import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION; +import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; -import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_AUTHORIZED; -import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_SUPPORTED; -import static android.telephony.satellite.SatelliteManager.SATELLITE_NO_RESOURCES; -import static android.telephony.satellite.SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; -import static android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS; -import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; -import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ERROR; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_AUTHORIZED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_RESOURCES; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_FALSE; import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_TRUE; @@ -48,10 +61,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyVararg; import static org.mockito.ArgumentMatchers.eq; @@ -60,8 +75,10 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.annotation.NonNull; @@ -75,13 +92,19 @@ import android.os.ICancellationSignal; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; +import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceSpecificException; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; +import android.telephony.ServiceState; +import android.telephony.satellite.INtnSignalStrengthCallback; +import android.telephony.satellite.ISatelliteCapabilitiesCallback; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -94,7 +117,9 @@ import com.android.internal.R; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; @@ -105,6 +130,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -123,19 +149,22 @@ import java.util.concurrent.TimeUnit; public class SatelliteControllerTest extends TelephonyTest { private static final String TAG = "SatelliteControllerTest"; - private static final int EVENT_DEVICE_CONFIG_CHANGED = 29; - private static final long TIMEOUT = 500; private static final int SUB_ID = 0; private static final int SUB_ID1 = 1; private static final int MAX_BYTES_PER_OUT_GOING_DATAGRAM = 339; private static final String TEST_SATELLITE_TOKEN = "TEST_SATELLITE_TOKEN"; private static final String TEST_NEXT_SATELLITE_TOKEN = "TEST_NEXT_SATELLITE_TOKEN"; - private static final String[] EMPTY_SATELLITE_SERVICES_SUPPORTED_BY_PROVIDERS_STRING_ARRAY = {}; + private static final String[] EMPTY_STRING_ARRAY = {}; + private static final List<String> EMPTY_STRING_LIST = new ArrayList<>(); private static final int[] ACTIVE_SUB_IDS = {SUB_ID}; + private List<Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener>> + mCarrierConfigChangedListenerList = new ArrayList<>(); private TestSatelliteController mSatelliteControllerUT; private TestSharedPreferences mSharedPreferences; + private PersistableBundle mCarrierConfigBundle; + private ServiceState mServiceState2; @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @@ -148,6 +177,7 @@ public class SatelliteControllerTest extends TelephonyTest { private List<Integer> mIIntegerConsumerResults = new ArrayList<>(); @Mock private ISatelliteTransmissionUpdateCallback mStartTransmissionUpdateCallback; @Mock private ISatelliteTransmissionUpdateCallback mStopTransmissionUpdateCallback; + @Mock private FeatureFlags mFeatureFlags; private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0); private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() { @Override @@ -167,18 +197,22 @@ public class SatelliteControllerTest extends TelephonyTest { private Set<Integer> mSupportedRadioTechnologies = new HashSet<>(Arrays.asList( NT_RADIO_TECHNOLOGY_NR_NTN, NT_RADIO_TECHNOLOGY_EMTC_NTN, + NT_RADIO_TECHNOLOGY_NB_IOT_NTN, NT_RADIO_TECHNOLOGY_PROPRIETARY)); private SatelliteCapabilities mSatelliteCapabilities = new SatelliteCapabilities( mSupportedRadioTechnologies, mIsPointingRequired, MAX_BYTES_PER_OUT_GOING_DATAGRAM, new HashMap<>()); + private SatelliteCapabilities mEmptySatelliteCapabilities = new SatelliteCapabilities( + new HashSet<>(), mIsPointingRequired, MAX_BYTES_PER_OUT_GOING_DATAGRAM, + new HashMap<>()); private Semaphore mSatelliteCapabilitiesSemaphore = new Semaphore(0); private SatelliteCapabilities mQueriedSatelliteCapabilities = null; - private int mQueriedSatelliteCapabilitiesResultCode = SATELLITE_ERROR_NONE; + private int mQueriedSatelliteCapabilitiesResultCode = SATELLITE_RESULT_SUCCESS; private ResultReceiver mSatelliteCapabilitiesReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedSatelliteCapabilitiesResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) { mQueriedSatelliteCapabilities = resultData.getParcelable( KEY_SATELLITE_CAPABILITIES, SatelliteCapabilities.class); @@ -199,13 +233,13 @@ public class SatelliteControllerTest extends TelephonyTest { }; private boolean mQueriedSatelliteSupported = false; - private int mQueriedSatelliteSupportedResultCode = SATELLITE_ERROR_NONE; + private int mQueriedSatelliteSupportedResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mSatelliteSupportSemaphore = new Semaphore(0); private ResultReceiver mSatelliteSupportReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedSatelliteSupportedResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) { mQueriedSatelliteSupported = resultData.getBoolean(KEY_SATELLITE_SUPPORTED); } else { @@ -225,14 +259,14 @@ public class SatelliteControllerTest extends TelephonyTest { }; private boolean mQueriedIsSatelliteEnabled = false; - private int mQueriedIsSatelliteEnabledResultCode = SATELLITE_ERROR_NONE; + private int mQueriedIsSatelliteEnabledResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mIsSatelliteEnabledSemaphore = new Semaphore(0); private ResultReceiver mIsSatelliteEnabledReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { logd("mIsSatelliteEnabledReceiver: resultCode=" + resultCode); mQueriedIsSatelliteEnabledResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_ENABLED)) { mQueriedIsSatelliteEnabled = resultData.getBoolean(KEY_SATELLITE_ENABLED); } else { @@ -251,13 +285,13 @@ public class SatelliteControllerTest extends TelephonyTest { }; private boolean mQueriedIsDemoModeEnabled = false; - private int mQueriedIsDemoModeEnabledResultCode = SATELLITE_ERROR_NONE; + private int mQueriedIsDemoModeEnabledResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mIsDemoModeEnabledSemaphore = new Semaphore(0); private ResultReceiver mIsDemoModeEnabledReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedIsDemoModeEnabledResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) { mQueriedIsDemoModeEnabled = resultData.getBoolean(KEY_DEMO_MODE_ENABLED); } else { @@ -277,13 +311,13 @@ public class SatelliteControllerTest extends TelephonyTest { }; private boolean mQueriedIsSatelliteProvisioned = false; - private int mQueriedIsSatelliteProvisionedResultCode = SATELLITE_ERROR_NONE; + private int mQueriedIsSatelliteProvisionedResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mIsSatelliteProvisionedSemaphore = new Semaphore(0); private ResultReceiver mIsSatelliteProvisionedReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedIsSatelliteProvisionedResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) { mQueriedIsSatelliteProvisioned = resultData.getBoolean(KEY_SATELLITE_PROVISIONED); @@ -304,13 +338,13 @@ public class SatelliteControllerTest extends TelephonyTest { }; private boolean mQueriedSatelliteAllowed = false; - private int mQueriedSatelliteAllowedResultCode = SATELLITE_ERROR_NONE; + private int mQueriedSatelliteAllowedResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mSatelliteAllowedSemaphore = new Semaphore(0); private ResultReceiver mSatelliteAllowedReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedSatelliteAllowedResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { mQueriedSatelliteAllowed = resultData.getBoolean( KEY_SATELLITE_COMMUNICATION_ALLOWED); @@ -319,7 +353,7 @@ public class SatelliteControllerTest extends TelephonyTest { mQueriedSatelliteAllowed = false; } } else { - logd("mSatelliteSupportReceiver: resultCode=" + resultCode); + logd("mSatelliteAllowedReceiver: resultCode=" + resultCode); mQueriedSatelliteAllowed = false; } try { @@ -332,13 +366,13 @@ public class SatelliteControllerTest extends TelephonyTest { private int mQueriedSatelliteVisibilityTime = -1; private int mSatelliteNextVisibilityTime = 3600; - private int mQueriedSatelliteVisibilityTimeResultCode = SATELLITE_ERROR_NONE; + private int mQueriedSatelliteVisibilityTimeResultCode = SATELLITE_RESULT_SUCCESS; private Semaphore mSatelliteVisibilityTimeSemaphore = new Semaphore(0); private ResultReceiver mSatelliteVisibilityTimeReceiver = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mQueriedSatelliteVisibilityTimeResultCode = resultCode; - if (resultCode == SATELLITE_ERROR_NONE) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) { mQueriedSatelliteVisibilityTime = resultData.getInt( KEY_SATELLITE_NEXT_VISIBILITY); @@ -358,9 +392,35 @@ public class SatelliteControllerTest extends TelephonyTest { } }; - private List<Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener>> - mCarrierConfigChangedListenerList = new ArrayList<>(); - private PersistableBundle mCarrierConfigBundle; + private @NtnSignalStrength.NtnSignalStrengthLevel int mQueriedNtnSignalStrengthLevel = + NTN_SIGNAL_STRENGTH_NONE; + private int mQueriedNtnSignalStrengthResultCode = SATELLITE_RESULT_SUCCESS; + private Semaphore mRequestNtnSignalStrengthSemaphore = new Semaphore(0); + private ResultReceiver mRequestNtnSignalStrengthReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedNtnSignalStrengthResultCode = resultCode; + if (resultCode == SATELLITE_RESULT_SUCCESS) { + if (resultData.containsKey(KEY_NTN_SIGNAL_STRENGTH)) { + NtnSignalStrength result = resultData.getParcelable(KEY_NTN_SIGNAL_STRENGTH); + logd("result.getLevel()=" + result.getLevel()); + mQueriedNtnSignalStrengthLevel = result.getLevel(); + } else { + loge("KEY_NTN_SIGNAL_STRENGTH does not exist."); + mQueriedNtnSignalStrengthLevel = NTN_SIGNAL_STRENGTH_NONE; + } + } else { + logd("KEY_NTN_SIGNAL_STRENGTH: resultCode=" + resultCode); + mQueriedNtnSignalStrengthLevel = NTN_SIGNAL_STRENGTH_NONE; + } + try { + mRequestNtnSignalStrengthSemaphore.release(); + } catch (Exception ex) { + loge("mRequestNtnSignalStrengthReceiver: Got exception in releasing semaphore, ex=" + + ex); + } + } + }; @Before public void setUp() throws Exception { @@ -384,10 +444,17 @@ public class SatelliteControllerTest extends TelephonyTest { mMockSessionMetricsStats); replaceInstance(SubscriptionManagerService.class, "sInstance", null, mMockSubscriptionManagerService); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mPhone2}); + + mServiceState2 = Mockito.mock(ServiceState.class); + when(mPhone.getServiceState()).thenReturn(mServiceState); + when(mPhone.getSubId()).thenReturn(SUB_ID); + when(mPhone2.getServiceState()).thenReturn(mServiceState2); + when(mPhone2.getSubId()).thenReturn(SUB_ID1); mContextFixture.putStringArrayResource( - R.array.config_satellite_services_supported_by_providers, - EMPTY_SATELLITE_SERVICES_SUPPORTED_BY_PROVIDERS_STRING_ARRAY); + R.array.config_satellite_providers, + EMPTY_STRING_ARRAY); doReturn(ACTIVE_SUB_IDS).when(mMockSubscriptionManagerService).getActiveSubIdList(true); mCarrierConfigBundle = mContextFixture.getCarrierConfigBundle(); @@ -407,11 +474,13 @@ public class SatelliteControllerTest extends TelephonyTest { doReturn(mIsSatelliteServiceSupported) .when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); setUpResponseForRequestSatelliteCapabilities( - mSatelliteCapabilities, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + mSatelliteCapabilities, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(false, + SATELLITE_RESULT_RADIO_NOT_AVAILABLE); doNothing().when(mMockDatagramController).setDemoMode(anyBoolean()); doNothing().when(mMockSatelliteSessionController) .onSatelliteEnabledStateChanged(anyBoolean()); + doNothing().when(mMockSatelliteSessionController).onSatelliteModemStateChanged(anyInt()); doNothing().when(mMockSatelliteSessionController).setDemoMode(anyBoolean()); doNothing().when(mMockControllerMetricsStats).onSatelliteEnabled(); doNothing().when(mMockControllerMetricsStats).reportServiceEnablementSuccessCount(); @@ -425,10 +494,12 @@ public class SatelliteControllerTest extends TelephonyTest { doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats) .setResultCode(anyInt()); doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats) - .setIsProvisionRequest(eq(false)); + .setIsProvisionRequest(eq(false)); doNothing().when(mMockProvisionMetricsStats).reportProvisionMetrics(); doNothing().when(mMockControllerMetricsStats).reportDeprovisionCount(anyInt()); - mSatelliteControllerUT = new TestSatelliteController(mContext, Looper.myLooper()); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + mSatelliteControllerUT = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); verify(mMockSatelliteModemInterface).registerForSatelliteProvisionStateChanged( any(Handler.class), eq(26) /* EVENT_SATELLITE_PROVISION_STATE_CHANGED */, @@ -453,135 +524,141 @@ public class SatelliteControllerTest extends TelephonyTest { @Test public void testRequestIsSatelliteCommunicationAllowedForCurrentLocation() { mSatelliteAllowedSemaphore.drainPermits(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, mSatelliteAllowedReceiver); processAllMessages(); assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteAllowedResultCode); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, mQueriedSatelliteAllowedResultCode); resetSatelliteControllerUT(); mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, mSatelliteAllowedReceiver); processAllMessages(); assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteAllowedForCurrentLocation(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteAllowedForCurrentLocation(true, + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, mSatelliteAllowedReceiver); processAllMessages(); assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteAllowedResultCode); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteAllowedResultCode); assertTrue(mQueriedSatelliteAllowed); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, mSatelliteAllowedReceiver); processAllMessages(); assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation( - SATELLITE_INVALID_MODEM_STATE); + SATELLITE_RESULT_INVALID_MODEM_STATE); mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, mSatelliteAllowedReceiver); processAllMessages(); assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteAllowedResultCode); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, mQueriedSatelliteAllowedResultCode); } @Test public void testRequestTimeForNextSatelliteVisibility() { mSatelliteVisibilityTimeSemaphore.drainPermits(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, mQueriedSatelliteVisibilityTimeResultCode); resetSatelliteControllerUT(); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + mQueriedSatelliteVisibilityTimeResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + mQueriedSatelliteVisibilityTimeResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + mQueriedSatelliteVisibilityTimeResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteVisibilityTimeResultCode); assertEquals(mSatelliteNextVisibilityTime, mQueriedSatelliteVisibilityTime); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); setUpNullResponseForRequestTimeForNextSatelliteVisibility( - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + mQueriedSatelliteVisibilityTimeResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); setUpNullResponseForRequestTimeForNextSatelliteVisibility( - SATELLITE_INVALID_MODEM_STATE); + SATELLITE_RESULT_INVALID_MODEM_STATE); mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, mSatelliteVisibilityTimeReceiver); processAllMessages(); assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, + mQueriedSatelliteVisibilityTimeResultCode); } @Test @@ -593,16 +670,17 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); // Fail to enable satellite when the device does not support satellite. mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); // Fail to enable satellite when the device is not provisioned yet. mIIntegerConsumerResults.clear(); @@ -610,28 +688,29 @@ public class SatelliteControllerTest extends TelephonyTest { verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(false)); verify(mMockSatelliteSessionController, times(1)).setDemoMode(eq(false)); verify(mMockDatagramController, times(1)).setDemoMode(eq(false)); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + (long) mIIntegerConsumerResults.get(0)); sendProvisionedStateChangedEvent(true, null); processAllMessages(); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); // Successfully enable satellite mIIntegerConsumerResults.clear(); mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); assertEquals( SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue); @@ -644,12 +723,13 @@ public class SatelliteControllerTest extends TelephonyTest { // Successfully disable satellite when radio is turned off. mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS); setRadioPower(false); + mSatelliteControllerUT.onCellularRadioPowerOffRequested(); processAllMessages(); sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_OFF, null); processAllMessages(); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); assertEquals( SATELLITE_MODE_ENABLED_FALSE, mSatelliteControllerUT.satelliteModeSettingValue); @@ -660,27 +740,27 @@ public class SatelliteControllerTest extends TelephonyTest { // Fail to enable satellite when radio is off. mIIntegerConsumerResults.clear(); - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); // Radio is not on, can not enable satellite - assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); setRadioPower(true); processAllMessages(); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); // Fail to enable satellite with an error response from modem when radio is on. mIIntegerConsumerResults.clear(); clearInvocations(mMockPointingAppController); mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_INVALID_MODEM_STATE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_INVALID_MODEM_STATE); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); verify(mMockPointingAppController, never()).startPointingUI(anyBoolean()); assertFalse(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); verify(mMockControllerMetricsStats, times(1)).reportServiceEnablementFailCount(); @@ -688,12 +768,12 @@ public class SatelliteControllerTest extends TelephonyTest { // Successfully enable satellite when radio is on. mIIntegerConsumerResults.clear(); mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); assertEquals(SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue); verify(mMockPointingAppController).startPointingUI(eq(false)); @@ -702,50 +782,50 @@ public class SatelliteControllerTest extends TelephonyTest { verify(mMockDatagramController, times(4)).setDemoMode(eq(false)); verify(mMockControllerMetricsStats, times(2)).onSatelliteEnabled(); verify(mMockControllerMetricsStats, times(2)).reportServiceEnablementSuccessCount(); - verify(mMockSessionMetricsStats, times(3)).setInitializationResult(anyInt()); - verify(mMockSessionMetricsStats, times(3)).setRadioTechnology(anyInt()); - verify(mMockSessionMetricsStats, times(3)).reportSessionMetrics(); + verify(mMockSessionMetricsStats, times(7)).setInitializationResult(anyInt()); + verify(mMockSessionMetricsStats, times(7)).setRadioTechnology(anyInt()); + verify(mMockSessionMetricsStats, times(7)).reportSessionMetrics(); // Successfully enable satellite when it is already enabled. mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); // Fail to enable satellite with a different demo mode when it is already enabled. mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_ARGUMENTS, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_INVALID_ARGUMENTS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); // Successfully disable satellite. mIIntegerConsumerResults.clear(); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); // Disable satellite when satellite is already disabled. mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); // Disable satellite with a different demo mode when satellite is already disabled. mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); // Send a second request while the first request in progress mIIntegerConsumerResults.clear(); @@ -756,13 +836,13 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_REQUEST_IN_PROGRESS, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_REQUEST_IN_PROGRESS, (long) mIIntegerConsumerResults.get(0)); mIIntegerConsumerResults.clear(); resetSatelliteControllerUTToSupportedAndProvisionedState(); // Should receive callback for the above request when satellite modem is turned off. assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); // Move to satellite-disabling in progress. setUpNoResponseForRequestSatelliteEnabled(false, false); @@ -775,53 +855,62 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_ERROR, (long) mIIntegerConsumerResults.get(0)); mIIntegerConsumerResults.clear(); resetSatelliteControllerUTToOffAndProvisionedState(); // Should receive callback for the above request when satellite modem is turned off. assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); /** * Make areAllRadiosDisabled return false and move mWaitingForRadioDisabled to true, which * will lead to no response for requestSatelliteEnabled. */ mSatelliteControllerUT.allRadiosDisabled = false; - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertFalse(waitForIIntegerConsumerResult(1)); resetSatelliteControllerUTEnabledState(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); // We should receive 2 callbacks for the above 2 requests. assertTrue(waitForIIntegerConsumerResult(2)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(1)); resetSatelliteControllerUTToOffAndProvisionedState(); // Repeat the same test as above but with error response from modem for the second request mSatelliteControllerUT.allRadiosDisabled = false; - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertFalse(waitForIIntegerConsumerResult(1)); resetSatelliteControllerUTEnabledState(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_NO_RESOURCES); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_NO_RESOURCES); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); // We should receive 2 callbacks for the above 2 requests. assertTrue(waitForIIntegerConsumerResult(2)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - assertEquals(SATELLITE_NO_RESOURCES, (long) mIIntegerConsumerResults.get(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NO_RESOURCES, (long) mIIntegerConsumerResults.get(1)); mSatelliteControllerUT.allRadiosDisabled = true; + + resetSatelliteControllerUTToOnAndProvisionedState(); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + mSatelliteControllerUT.onCellularRadioPowerOffRequested(); + processAllMessages(); + // Satellite should not be powered off since the feature flag oemEnabledSatelliteFlag is + // disabled + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); } @Test @@ -830,42 +919,48 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + mQueriedSatelliteCapabilitiesResultCode); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, mQueriedSatelliteCapabilitiesResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestSatelliteCapabilities(mSatelliteCapabilities, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteCapabilities(mSatelliteCapabilities, + SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode); assertEquals(mSatelliteCapabilities, mQueriedSatelliteCapabilities); + assertTrue( + mQueriedSatelliteCapabilities.getSupportedRadioTechnologies().contains( + mSatelliteControllerUT.getSupportedNtnRadioTechnology())); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + mQueriedSatelliteCapabilitiesResultCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_INVALID_MODEM_STATE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_RESULT_INVALID_MODEM_STATE); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, mQueriedSatelliteCapabilitiesResultCode); } @Test @@ -876,72 +971,75 @@ public class SatelliteControllerTest extends TelephonyTest { mStartTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStartTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStartTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); - setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStartTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStartTransmissionUpdateCallback); verify(mMockPointingAppController).registerForSatelliteTransmissionUpdates(anyInt(), - eq(mStartTransmissionUpdateCallback), any()); + eq(mStartTransmissionUpdateCallback)); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verify(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class), - any(Phone.class)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verify(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class)); verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(true)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_INVALID_TELEPHONY_STATE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_RESULT_INVALID_TELEPHONY_STATE); mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStartTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(), - any(), eq(mStartTransmissionUpdateCallback), any(Phone.class)); + any(), eq(mStartTransmissionUpdateCallback)); verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(false)); } @@ -953,69 +1051,72 @@ public class SatelliteControllerTest extends TelephonyTest { mStopTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStopTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStopTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); - setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStopTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStopTransmissionUpdateCallback); verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(), - any(), eq(mStopTransmissionUpdateCallback), any(Phone.class)); + any(), eq(mStopTransmissionUpdateCallback)); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verify(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class), - any(Phone.class)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verify(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_INVALID_TELEPHONY_STATE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_RESULT_INVALID_TELEPHONY_STATE); mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, mStopTransmissionUpdateCallback); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); } @Test @@ -1024,51 +1125,51 @@ public class SatelliteControllerTest extends TelephonyTest { resetSatelliteControllerUT(); mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); assertTrue(waitForRequestIsDemoModeEnabledResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); assertFalse(mQueriedIsDemoModeEnabled); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); assertTrue(waitForRequestIsDemoModeEnabledResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedIsDemoModeEnabledResultCode); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, mQueriedIsDemoModeEnabledResultCode); assertFalse(mQueriedIsDemoModeEnabled); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); assertTrue(waitForRequestIsDemoModeEnabledResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); assertFalse(mQueriedIsDemoModeEnabled); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); assertTrue(waitForRequestIsDemoModeEnabledResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mQueriedIsDemoModeEnabledResultCode); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, mQueriedIsDemoModeEnabledResultCode); assertFalse(mQueriedIsDemoModeEnabled); resetSatelliteControllerUT(); boolean isDemoModeEnabled = mSatelliteControllerUT.isDemoModeEnabled(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); assertTrue(waitForRequestIsDemoModeEnabledResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mQueriedIsDemoModeEnabledResultCode); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedIsDemoModeEnabledResultCode); assertEquals(isDemoModeEnabled, mQueriedIsDemoModeEnabled); } @Test public void testIsSatelliteEnabled() { assertFalse(mSatelliteControllerUT.isSatelliteEnabled()); - setUpResponseForRequestIsSatelliteEnabled(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); mIsSatelliteEnabledSemaphore.drainPermits(); mSatelliteControllerUT.requestIsSatelliteEnabled(SUB_ID, mIsSatelliteEnabledReceiver); processAllMessages(); @@ -1078,20 +1179,20 @@ public class SatelliteControllerTest extends TelephonyTest { @Test public void testOnSatelliteServiceConnected() { - verifySatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); - verifySatelliteEnabled(false, SATELLITE_INVALID_TELEPHONY_STATE); - verifySatelliteProvisioned(false, SATELLITE_INVALID_TELEPHONY_STATE); + verifySatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE); + verifySatelliteEnabled(false, SATELLITE_RESULT_INVALID_TELEPHONY_STATE); + verifySatelliteProvisioned(false, SATELLITE_RESULT_INVALID_TELEPHONY_STATE); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.onSatelliteServiceConnected(); processAllMessages(); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); } @Test @@ -1104,7 +1205,7 @@ public class SatelliteControllerTest extends TelephonyTest { }; int errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( SUB_ID, callback); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, errorCode); verify(mMockSatelliteSessionController, never()) .registerForSatelliteModemStateChanged(callback); @@ -1112,7 +1213,7 @@ public class SatelliteControllerTest extends TelephonyTest { errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( SUB_ID, callback); - assertEquals(SATELLITE_ERROR_NONE, errorCode); + assertEquals(SATELLITE_RESULT_SUCCESS, errorCode); verify(mMockSatelliteSessionController).registerForSatelliteModemStateChanged(callback); } @@ -1152,20 +1253,20 @@ public class SatelliteControllerTest extends TelephonyTest { }; int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( SUB_ID, callback); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, errorCode); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( SUB_ID, callback); - assertEquals(SATELLITE_NOT_SUPPORTED, errorCode); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, errorCode); resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( SUB_ID, callback); - assertEquals(SATELLITE_ERROR_NONE, errorCode); + assertEquals(SATELLITE_RESULT_SUCCESS, errorCode); sendProvisionedStateChangedEvent(true, null); processAllMessages(); @@ -1191,9 +1292,9 @@ public class SatelliteControllerTest extends TelephonyTest { } }; when(mMockDatagramController.registerForSatelliteDatagram(eq(SUB_ID), eq(callback))) - .thenReturn(SATELLITE_ERROR_NONE); + .thenReturn(SATELLITE_RESULT_SUCCESS); int errorCode = mSatelliteControllerUT.registerForSatelliteDatagram(SUB_ID, callback); - assertEquals(SATELLITE_ERROR_NONE, errorCode); + assertEquals(SATELLITE_RESULT_SUCCESS, errorCode); verify(mMockDatagramController).registerForSatelliteDatagram(eq(SUB_ID), eq(callback)); } @@ -1224,22 +1325,24 @@ public class SatelliteControllerTest extends TelephonyTest { SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); verify(mMockDatagramController, never()).sendSatelliteDatagram(anyInt(), eq(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE), eq(datagram), eq(true), any()); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); sendProvisionedStateChangedEvent(false, null); processAllMessages(); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.sendSatelliteDatagram(SUB_ID, SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + (long) mIIntegerConsumerResults.get(0)); verify(mMockDatagramController, never()).sendSatelliteDatagram(anyInt(), eq(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE), eq(datagram), eq(true), any()); @@ -1247,7 +1350,7 @@ public class SatelliteControllerTest extends TelephonyTest { mIIntegerConsumerResults.clear(); sendProvisionedStateChangedEvent(true, null); processAllMessages(); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.sendSatelliteDatagram(SUB_ID, SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); processAllMessages(); @@ -1264,25 +1367,27 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any()); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); sendProvisionedStateChangedEvent(false, null); processAllMessages(); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, + (long) mIIntegerConsumerResults.get(0)); verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any()); mIIntegerConsumerResults.clear(); sendProvisionedStateChangedEvent(true, null); processAllMessages(); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); processAllMessages(); assertFalse(waitForIIntegerConsumerResult(1)); @@ -1301,94 +1406,95 @@ public class SatelliteControllerTest extends TelephonyTest { testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); assertNull(cancelRemote); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); assertNull(cancelRemote); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); assertNull(cancelRemote); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); setUpResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN, testProvisionData, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); assertNotNull(cancelRemote); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); setUpResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN, testProvisionData, - SATELLITE_NOT_AUTHORIZED); + SATELLITE_RESULT_NOT_AUTHORIZED); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_AUTHORIZED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_AUTHORIZED, (long) mIIntegerConsumerResults.get(0)); assertNotNull(cancelRemote); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); setUpResponseForProvisionSatelliteService(TEST_NEXT_SATELLITE_TOKEN, testProvisionData, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_NEXT_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); cancellationSignal.setRemote(cancelRemote); cancellationSignal.cancel(); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); verify(mMockSatelliteModemInterface).deprovisionSatelliteService( eq(TEST_NEXT_SATELLITE_TOKEN), any(Message.class)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); setUpNoResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN); setUpResponseForProvisionSatelliteService(TEST_NEXT_SATELLITE_TOKEN, testProvisionData, - SATELLITE_ERROR_NONE); + SATELLITE_RESULT_SUCCESS); cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); @@ -1397,7 +1503,7 @@ public class SatelliteControllerTest extends TelephonyTest { testProvisionData, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_PROVISION_IN_PROGRESS, + assertEquals(SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS, (long) mIIntegerConsumerResults.get(0)); } @@ -1405,123 +1511,126 @@ public class SatelliteControllerTest extends TelephonyTest { public void testDeprovisionSatelliteService() { mIIntegerConsumerSemaphore.drainPermits(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, - TEST_SATELLITE_TOKEN, mIIntegerConsumer); + TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, + (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); - setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); mIIntegerConsumerResults.clear(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, - SATELLITE_INVALID_MODEM_STATE); + SATELLITE_RESULT_INVALID_MODEM_STATE); mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, TEST_SATELLITE_TOKEN, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); } @Test public void testSupportedSatelliteServices() { - List<String> satellitePlmnList = mSatelliteControllerUT.getSatellitePlmnList(); - assertEquals(EMPTY_SATELLITE_SERVICES_SUPPORTED_BY_PROVIDERS_STRING_ARRAY.length, - satellitePlmnList.size()); + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + List<String> satellitePlmnList = mSatelliteControllerUT.getSatellitePlmnList(SUB_ID); + assertEquals(EMPTY_STRING_ARRAY.length, satellitePlmnList.size()); List<Integer> supportedSatelliteServices = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00101"); assertTrue(supportedSatelliteServices.isEmpty()); - String[] satellitePlmnArray = {"00101", "00102"}; - String[] satelliteServicesSupportedByProviderStrArray = {"00101:1,2", "00102:2,3"}; - int[] expectedSupportedServices1 = {1, 2}; - int[] expectedSupportedServices2 = {2, 3}; - + String[] satelliteProviderStrArray = {"00101", "00102"}; mContextFixture.putStringArrayResource( - R.array.config_satellite_services_supported_by_providers, - satelliteServicesSupportedByProviderStrArray); + R.array.config_satellite_providers, satelliteProviderStrArray); + int[] expectedSupportedServices2 = {2}; + int[] expectedSupportedServices3 = {1, 3}; + PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle(); + carrierSupportedSatelliteServicesPerProvider.putIntArray( + "00102", expectedSupportedServices2); + carrierSupportedSatelliteServicesPerProvider.putIntArray( + "00103", expectedSupportedServices3); + String[] expectedSupportedSatellitePlmns = {"00102", "00103"}; + mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager + .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + carrierSupportedSatelliteServicesPerProvider); TestSatelliteController testSatelliteController = - new TestSatelliteController(mContext, Looper.myLooper()); - - satellitePlmnList = testSatelliteController.getSatellitePlmnList(); - assertTrue(Arrays.equals(satellitePlmnArray, satellitePlmnList.stream().toArray())); + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + assertTrue(satellitePlmnList.isEmpty()); supportedSatelliteServices = testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101"); - assertNotNull(supportedSatelliteServices); - assertTrue(Arrays.equals(expectedSupportedServices1, - supportedSatelliteServices.stream() - .mapToInt(Integer::intValue) - .toArray())); + assertTrue(supportedSatelliteServices.isEmpty()); + + // Carrier config changed with carrierEnabledSatelliteFlag disabled + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); supportedSatelliteServices = testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102"); - assertNotNull(supportedSatelliteServices); - assertTrue(Arrays.equals(expectedSupportedServices2, - supportedSatelliteServices.stream() - .mapToInt(Integer::intValue) - .toArray())); + assertTrue(supportedSatelliteServices.isEmpty()); + supportedSatelliteServices = + testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103"); + assertTrue(supportedSatelliteServices.isEmpty()); - // Carrier config changed - int[] expectedSupportedServices3 = {2}; - int[] supportedServices = {1, 3}; - PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle(); - carrierSupportedSatelliteServicesPerProvider.putIntArray( - "00102", expectedSupportedServices3); - carrierSupportedSatelliteServicesPerProvider.putIntArray("00103", supportedServices); - mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager - .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, - carrierSupportedSatelliteServicesPerProvider); + // Trigger carrier config changed with carrierEnabledSatelliteFlag enabled + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair : mCarrierConfigChangedListenerList) { pair.first.execute(() -> pair.second.onCarrierConfigChanged( @@ -1530,26 +1639,22 @@ public class SatelliteControllerTest extends TelephonyTest { } processAllMessages(); + satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + assertTrue(Arrays.equals( + expectedSupportedSatellitePlmns, satellitePlmnList.stream().toArray())); supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101"); - assertNotNull(supportedSatelliteServices); - assertTrue(Arrays.equals(expectedSupportedServices1, + mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00102"); + assertTrue(Arrays.equals(expectedSupportedServices2, supportedSatelliteServices.stream() .mapToInt(Integer::intValue) .toArray())); - supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102"); - assertNotNull(supportedSatelliteServices); + mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00103"); assertTrue(Arrays.equals(expectedSupportedServices3, supportedSatelliteServices.stream() .mapToInt(Integer::intValue) .toArray())); - supportedSatelliteServices = - mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00103"); - assertTrue(supportedSatelliteServices.isEmpty()); - // Subscriptions changed int[] newActiveSubIds = {SUB_ID1}; doReturn(newActiveSubIds).when(mMockSubscriptionManagerService).getActiveSubIdList(true); @@ -1561,47 +1666,902 @@ public class SatelliteControllerTest extends TelephonyTest { } processAllMessages(); + satellitePlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + assertTrue(satellitePlmnList.isEmpty()); supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101"); + testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102"); assertTrue(supportedSatelliteServices.isEmpty()); supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102"); + testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103"); assertTrue(supportedSatelliteServices.isEmpty()); + supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00101"); + testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00102"); assertNotNull(supportedSatelliteServices); - assertTrue(Arrays.equals(expectedSupportedServices1, + assertTrue(Arrays.equals(expectedSupportedServices2, supportedSatelliteServices.stream() .mapToInt(Integer::intValue) .toArray())); supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00102"); - assertNotNull(supportedSatelliteServices); + testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00103"); assertTrue(Arrays.equals(expectedSupportedServices3, supportedSatelliteServices.stream() .mapToInt(Integer::intValue) .toArray())); + } - supportedSatelliteServices = - testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00103"); - assertTrue(supportedSatelliteServices.isEmpty()); + @Test + public void testConfigureSatellitePlmnOnCarrierConfigChanged() { + logd("testConfigureSatellitePlmnOnCarrierConfigChanged"); + + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + String[] satelliteProviderStrArray = + {"00101", "00102", "00103", "00104", "00105"}; + List<String> satellitePlmnListFromOverlayConfig = + Arrays.stream(satelliteProviderStrArray).toList(); + mContextFixture.putStringArrayResource( + R.array.config_satellite_providers, satelliteProviderStrArray); + + /* Initially, the radio state is ON. In the constructor, satelliteController registers for + the radio state changed events and immediately gets the radio state changed event as ON. */ + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + mCarrierConfigChangedListenerList.clear(); + TestSatelliteController testSatelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + processAllMessages(); + List<String> carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + verify(mMockSatelliteModemInterface, never()).setSatellitePlmn( + anyInt(), anyList(), anyList(), any(Message.class)); + assertTrue(carrierPlmnList.isEmpty()); + reset(mMockSatelliteModemInterface); + + // Test setSatellitePlmn() when Carrier Config change event triggered. + mCarrierConfigBundle.putBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, + true); + int[] supportedServices2 = {2}; + int[] supportedServices3 = {1, 3}; + PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle(); + carrierSupportedSatelliteServicesPerProvider.putIntArray( + "00102", supportedServices2); + carrierSupportedSatelliteServicesPerProvider.putIntArray( + "00103", supportedServices3); + List<String> expectedCarrierPlmnList = Arrays.asList("00102", "00103"); + mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager + .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + carrierSupportedSatelliteServicesPerProvider); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + verify(mMockSatelliteModemInterface, never()).setSatellitePlmn( + anyInt(), anyList(), anyList(), any(Message.class)); + assertTrue(carrierPlmnList.isEmpty()); + reset(mMockSatelliteModemInterface); + + // Reset TestSatelliteController so that device satellite PLMNs is loaded when + // carrierEnabledSatelliteFlag is enabled. + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mCarrierConfigChangedListenerList.clear(); + testSatelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + + // Trigger carrier config changed with carrierEnabledSatelliteFlag enabled and empty + // carrier supported satellite services. + mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager + .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + new PersistableBundle()); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + + carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + assertTrue(carrierPlmnList.isEmpty()); + List<String> allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists( + carrierPlmnList, satellitePlmnListFromOverlayConfig); + verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(), + eq(EMPTY_STRING_LIST), eq(allSatellitePlmnList), any(Message.class)); + reset(mMockSatelliteModemInterface); + + // Trigger carrier config changed with carrierEnabledSatelliteFlag enabled and non-empty + // carrier supported satellite services. + mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager + .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + carrierSupportedSatelliteServicesPerProvider); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists( + carrierPlmnList, satellitePlmnListFromOverlayConfig); + assertEquals(expectedCarrierPlmnList, carrierPlmnList); + verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(), + eq(carrierPlmnList), eq(allSatellitePlmnList), any(Message.class)); + reset(mMockSatelliteModemInterface); + + /* setSatellitePlmn() is called regardless whether satellite attach for carrier is + supported. */ + mCarrierConfigBundle.putBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, + false); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(), + eq(carrierPlmnList), eq(allSatellitePlmnList), any(Message.class)); + reset(mMockSatelliteModemInterface); + + // Test empty config_satellite_providers and empty carrier PLMN list + mCarrierConfigChangedListenerList.clear(); + mContextFixture.putStringArrayResource( + R.array.config_satellite_providers, EMPTY_STRING_ARRAY); + testSatelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager + .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE, + new PersistableBundle()); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + carrierPlmnList = testSatelliteController.getSatellitePlmnList(SUB_ID); + assertTrue(carrierPlmnList.isEmpty()); + verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(), + eq(EMPTY_STRING_LIST), eq(EMPTY_STRING_LIST), any(Message.class)); + reset(mMockSatelliteModemInterface); + } + + @Test + public void testSatelliteCommunicationRestriction() { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mCarrierConfigBundle.putBoolean( + CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + + // Remove restriction reason if exist + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSetSatelliteEnabledForCarrier(false, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(2)); + + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(1)); + + Set<Integer> restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(!restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)); + assertTrue(!restrictionSet.contains( + SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION)); + + // Add satellite attach restriction reason by user + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(false, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + mSatelliteControllerUT.addSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + processAllMessages(); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verify(mMockSatelliteModemInterface, never()) + .requestSetSatelliteEnabledForCarrier(anyInt(), anyBoolean(), any(Message.class)); + assertTrue(waitForIIntegerConsumerResult(1)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)); + + // remove satellite restriction reason by user + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(true, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(!restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)); + verify(mMockSatelliteModemInterface, times(1)) + .requestSetSatelliteEnabledForCarrier(anyInt(), anyBoolean(), any(Message.class)); + + // Add satellite attach restriction reason by user + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(false, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + mSatelliteControllerUT.addSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)); + verify(mMockSatelliteModemInterface, times(1)) + .requestSetSatelliteEnabledForCarrier(anyInt(), eq(false), any(Message.class)); + + // add satellite attach restriction reason by geolocation + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(false, SATELLITE_RESULT_SUCCESS); + mSatelliteControllerUT.addSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION, mIIntegerConsumer); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION)); + verify(mMockSatelliteModemInterface, never()) + .requestSetSatelliteEnabledForCarrier(anyInt(), anyBoolean(), any(Message.class)); + + // remove satellite attach restriction reason by geolocation + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(true, SATELLITE_RESULT_SUCCESS); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION, mIIntegerConsumer); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(!restrictionSet.contains( + SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION)); + verify(mMockSatelliteModemInterface, never()) + .requestSetSatelliteEnabledForCarrier(anyInt(), anyBoolean(), any(Message.class)); + + // remove satellite restriction reason by user + mIIntegerConsumerResults.clear(); + reset(mMockSatelliteModemInterface); + setUpResponseForRequestSetSatelliteEnabledForCarrier(true, SATELLITE_RESULT_SUCCESS); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + restrictionSet = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(!restrictionSet.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)); + verify(mMockSatelliteModemInterface, times(1)) + .requestSetSatelliteEnabledForCarrier(anyInt(), eq(true), any(Message.class)); + reset(mMockSatelliteModemInterface); + + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.removeSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals( + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + verifyZeroInteractions(mMockSatelliteModemInterface); + + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.addSatelliteAttachRestrictionForCarrier(SUB_ID, + SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals( + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + verifyZeroInteractions(mMockSatelliteModemInterface); + + Set<Integer> satelliteRestrictionReasons = + mSatelliteControllerUT.getSatelliteAttachRestrictionReasonsForCarrier(SUB_ID); + assertTrue(satelliteRestrictionReasons.isEmpty()); + } + + @Test + public void testIsSatelliteAttachRequired() { + mSatelliteCapabilitiesSemaphore.drainPermits(); + TestSatelliteController satelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + satelliteController.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals( + SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedSatelliteCapabilitiesResultCode); + assertFalse(satelliteController.isSatelliteAttachRequired()); + + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteCapabilities( + mSatelliteCapabilities, SATELLITE_RESULT_MODEM_ERROR); + satelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteCapabilities( + mEmptySatelliteCapabilities, SATELLITE_RESULT_SUCCESS); + satelliteController.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(mEmptySatelliteCapabilities, mQueriedSatelliteCapabilities); + assertEquals(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN, + mSatelliteControllerUT.getSupportedNtnRadioTechnology()); + + assertFalse(satelliteController.isSatelliteAttachRequired()); + + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteCapabilities( + mSatelliteCapabilities, SATELLITE_RESULT_MODEM_ERROR); + satelliteController = + new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestSatelliteCapabilities( + mSatelliteCapabilities, SATELLITE_RESULT_SUCCESS); + satelliteController.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(mSatelliteCapabilities, mQueriedSatelliteCapabilities); + assertTrue( + mQueriedSatelliteCapabilities.getSupportedRadioTechnologies().contains( + satelliteController.getSupportedNtnRadioTechnology())); + assertTrue(satelliteController.isSatelliteAttachRequired()); + + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + assertFalse(satelliteController.isSatelliteAttachRequired()); + } + + @Test + public void testSatelliteModemStateChanged() { + clearInvocations(mMockSatelliteSessionController); + clearInvocations(mMockDatagramController); + sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_CONNECTED, null); + processAllMessages(); + verify(mMockSatelliteSessionController, times(0)).onSatelliteModemStateChanged( + SATELLITE_MODEM_STATE_CONNECTED); + + resetSatelliteControllerUTToSupportedAndProvisionedState(); + clearInvocations(mMockSatelliteSessionController); + clearInvocations(mMockDatagramController); + sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_UNAVAILABLE, null); + processAllMessages(); + verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(false)); + verify(mMockSatelliteSessionController, times(1)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(1)).setDemoMode(eq(false)); + + clearInvocations(mMockSatelliteSessionController); + clearInvocations(mMockDatagramController); + sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_CONNECTED, null); + processAllMessages(); + verify(mMockSatelliteSessionController, times(1)).onSatelliteModemStateChanged( + SATELLITE_MODEM_STATE_CONNECTED); + } + + @Test + public void testRequestNtnSignalStrengthWithFeatureFlagEnabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + + resetSatelliteControllerUT(); + + mRequestNtnSignalStrengthSemaphore.drainPermits(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + + @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_GREAT; + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + /* In case request is not successful, result should be NTN_SIGNAL_STRENGTH_NONE */ + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, SATELLITE_RESULT_NOT_SUPPORTED); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + // reset cache to NTN_SIGNAL_STRENGTH_NONE + sendNtnSignalStrengthChangedEvent(NTN_SIGNAL_STRENGTH_NONE, null); + processAllMessages(); + expectedLevel = NTN_SIGNAL_STRENGTH_POOR; + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + } + + @Test + public void testRequestNtnSignalStrengthWithFeatureFlagDisabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + + resetSatelliteControllerUT(); + mRequestNtnSignalStrengthSemaphore.drainPermits(); + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + + @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_GREAT; + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + expectedLevel = NTN_SIGNAL_STRENGTH_POOR; + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_MODEM_ERROR); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + } + + @Test + public void testRegisterForNtnSignalStrengthChangedWithFeatureFlagEnabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + + Semaphore semaphore = new Semaphore(0); + final NtnSignalStrength[] signalStrength = new NtnSignalStrength[1]; + INtnSignalStrengthCallback callback = + new INtnSignalStrengthCallback.Stub() { + @Override + public void onNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) { + logd("onNtnSignalStrengthChanged: ntnSignalStrength=" + + ntnSignalStrength); + try { + signalStrength[0] = ntnSignalStrength; + semaphore.release(); + } catch (Exception ex) { + loge("onNtnSignalStrengthChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_INVALID_TELEPHONY_STATE); + + setUpResponseForRequestIsSatelliteSupported(false, + SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_NOT_SUPPORTED); + + @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_NONE; + verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_NOT_SUPPORTED); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS); + + expectedLevel = NTN_SIGNAL_STRENGTH_GOOD; + sendNtnSignalStrengthChangedEvent(expectedLevel, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 1, "testRegisterForNtnSignalStrengthChanged")); + assertEquals(expectedLevel, signalStrength[0].getLevel()); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_GOOD, SATELLITE_RESULT_SUCCESS); + + expectedLevel = NTN_SIGNAL_STRENGTH_POOR; + sendNtnSignalStrengthChangedEvent(expectedLevel, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 1, "testRegisterForNtnSignalStrengthChanged")); + assertEquals(expectedLevel, signalStrength[0].getLevel()); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_POOR, SATELLITE_RESULT_SUCCESS); + + mSatelliteControllerUT.unregisterForNtnSignalStrengthChanged(SUB_ID, callback); + sendNtnSignalStrengthChangedEvent(NTN_SIGNAL_STRENGTH_GREAT, null); + processAllMessages(); + assertFalse(waitForForEvents( + semaphore, 1, "testRegisterForNtnSignalStrengthChanged")); + /* Even if all listeners are unregistered, the cache is updated with the latest value when a + new value event occurs. */ + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_GREAT, SATELLITE_RESULT_SUCCESS); + } + + @Test + public void testRegisterForNtnSignalStrengthChangedWithFeatureFlagDisabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + + Semaphore semaphore = new Semaphore(0); + final NtnSignalStrength[] signalStrength = new NtnSignalStrength[1]; + INtnSignalStrengthCallback callback = + new INtnSignalStrengthCallback.Stub() { + @Override + public void onNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) { + logd("onNtnSignalStrengthChanged: ntnSignalStrength=" + + ntnSignalStrength); + try { + signalStrength[0] = ntnSignalStrength; + semaphore.release(); + } catch (Exception ex) { + loge("onNtnSignalStrengthChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + setUpResponseForRequestIsSatelliteSupported(false, + SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED); + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + setUpResponseForRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_SUCCESS); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED); + verifyRegisterForNtnSignalStrengthChanged(SUB_ID, callback, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, + SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + + @NtnSignalStrength.NtnSignalStrengthLevel int expectedNtnSignalStrengthLevel = + NTN_SIGNAL_STRENGTH_GOOD; + sendNtnSignalStrengthChangedEvent(expectedNtnSignalStrengthLevel, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 0, "testRegisterForNtnSignalStrengthChanged")); + } + + @Test + public void testSendingNtnSignalStrengthWithFeatureEnabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + + int expectedResult = SATELLITE_RESULT_SUCCESS; + // startSendingNtnSignalStrength() is requested when screen on event comes. + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestIsSatelliteSupported(true, expectedResult); + setUpResponseForRequestIsSatelliteProvisioned(true, expectedResult); + verifySatelliteSupported(true, expectedResult); + verifySatelliteProvisioned(true, expectedResult); + setUpResponseForStartSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(true); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .startSendingNtnSignalStrength(any(Message.class)); + + // requested again but ignored as expected and current state are matched. + setUpResponseForStartSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(true); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .startSendingNtnSignalStrength(any(Message.class)); + + // stopSendingNtnSignalStrength() is requested when screen off event comes. + reset(mMockSatelliteModemInterface); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStopSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .stopSendingNtnSignalStrength(any(Message.class)); + + // requested again but ignored as expected and current state are matched. + setUpResponseForStopSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .stopSendingNtnSignalStrength(any(Message.class)); + + // startSendingNtnSignalStrength() is requested but received fail from the service. + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStartSendingNtnSignalStrength(SATELLITE_RESULT_INVALID_MODEM_STATE); + sendCmdStartSendingNtnSignalStrengthChangedEvent(true); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .startSendingNtnSignalStrength(any(Message.class)); + + /* stopSendingNtnSignalStrength() is ignored because startSendingNtnSignalStrength has + failed thus current state is stopSendingNtnSignalStrength */ + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStopSendingNtnSignalStrength(SATELLITE_RESULT_NO_RESOURCES); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, never()) + .stopSendingNtnSignalStrength(any(Message.class)); + + // startSendingNtnSignalStrength() is requested and modem state is changed + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStartSendingNtnSignalStrength(SATELLITE_RESULT_SUCCESS); + sendCmdStartSendingNtnSignalStrengthChangedEvent(true); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .startSendingNtnSignalStrength(any(Message.class)); + + // stopSendingNtnSignalStrength() is failed as modem returns error + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStopSendingNtnSignalStrength(SATELLITE_RESULT_NO_RESOURCES); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .stopSendingNtnSignalStrength(any(Message.class)); + + // request stopSendingNtnSignalStrength() again and returns success + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStopSendingNtnSignalStrength(SATELLITE_RESULT_SUCCESS); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, times(1)) + .stopSendingNtnSignalStrength(any(Message.class)); + } + + @Test + public void testSendingNtnSignalStrengthWithFeatureDisabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + + int expectedResult = SATELLITE_RESULT_SUCCESS; + // startSendingNtnSignalStrength() is requested when screen on event comes. + reset(mMockSatelliteModemInterface); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestIsSatelliteSupported(true, expectedResult); + setUpResponseForRequestIsSatelliteProvisioned(true, expectedResult); + verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED); + verifySatelliteProvisioned(false, SATELLITE_RESULT_REQUEST_NOT_SUPPORTED); + setUpResponseForStartSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(true); + processAllMessages(); + verify(mMockSatelliteModemInterface, never()) + .startSendingNtnSignalStrength(any(Message.class)); + + // stopSendingNtnSignalStrength() is requested when screen off event comes. + reset(mMockSatelliteModemInterface); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForStopSendingNtnSignalStrength(expectedResult); + sendCmdStartSendingNtnSignalStrengthChangedEvent(false); + processAllMessages(); + verify(mMockSatelliteModemInterface, never()) + .stopSendingNtnSignalStrength(any(Message.class)); + } + + @Test + public void testIsSatelliteSupportedViaCarrier() { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + assertFalse(mSatelliteControllerUT.isSatelliteSupportedViaCarrier()); + + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + assertFalse(mSatelliteControllerUT.isSatelliteSupportedViaCarrier()); + + mCarrierConfigBundle.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + assertTrue(mSatelliteControllerUT.isSatelliteSupportedViaCarrier()); + } + + @Test + public void testCarrierEnabledSatelliteConnectionHysteresisTime() { + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false); + assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + + when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true); + mCarrierConfigBundle.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 1 * 60); + mCarrierConfigBundle.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true); + for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair + : mCarrierConfigChangedListenerList) { + pair.first.execute(() -> pair.second.onCarrierConfigChanged( + /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0) + ); + } + processAllMessages(); + mSatelliteControllerUT.elapsedRealtime = 0; + assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + + when(mServiceState.isUsingNonTerrestrialNetwork()).thenReturn(false); + when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false); + sendServiceStateChangedEvent(); + processAllMessages(); + assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + + // Last satellite connected time of Phone2 should be 0 + when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(true); + sendServiceStateChangedEvent(); + processAllMessages(); + // 2 minutes later and hysteresis timeout is 1 minute + mSatelliteControllerUT.elapsedRealtime = 2 * 60 * 1000; + // But Phone2 is connected to NTN right now + assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + + // Last satellite disconnected time of Phone2 should be 2 * 60 * 1000 + when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false); + sendServiceStateChangedEvent(); + processAllMessages(); + // Current time (2) - last disconnected time (2) < hysteresis timeout (1) + assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + + // Current time (4) - last disconnected time (2) > hysteresis timeout (1) + mSatelliteControllerUT.elapsedRealtime = 4 * 60 * 1000; + assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime()); + } + + @Test + public void testRegisterForSatelliteCapabilitiesChangedWithFeatureFlagEnabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + + Semaphore semaphore = new Semaphore(0); + final SatelliteCapabilities[] satelliteCapabilities = new SatelliteCapabilities[1]; + ISatelliteCapabilitiesCallback callback = + new ISatelliteCapabilitiesCallback.Stub() { + @Override + public void onSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) { + logd("onSatelliteCapabilitiesChanged: " + capabilities); + try { + satelliteCapabilities[0] = capabilities; + semaphore.release(); + } catch (Exception ex) { + loge("onSatelliteCapabilitiesChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + + int errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, errorCode); + + setUpResponseForRequestIsSatelliteSupported(false, + SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS); + errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, errorCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteProvisioned(true, + SATELLITE_RESULT_SUCCESS); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_SUCCESS, errorCode); + SatelliteCapabilities expectedCapabilities = mSatelliteCapabilities; + sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 1, "testRegisterForSatelliteCapabilitiesChanged")); + assertTrue(expectedCapabilities.equals(satelliteCapabilities[0])); + + expectedCapabilities = mEmptySatelliteCapabilities; + sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 1, "testRegisterForSatelliteCapabilitiesChanged")); + assertTrue(expectedCapabilities.equals(satelliteCapabilities[0])); + + mSatelliteControllerUT.unregisterForSatelliteCapabilitiesChanged(SUB_ID, callback); + expectedCapabilities = mSatelliteCapabilities; + sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 0, "testRegisterForSatelliteCapabilitiesChanged")); + } + + @Test + public void testRegisterForSatelliteCapabilitiesChangedWithFeatureFlagDisabled() { + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + + Semaphore semaphore = new Semaphore(0); + final SatelliteCapabilities[] satelliteCapabilities = new SatelliteCapabilities[1]; + ISatelliteCapabilitiesCallback callback = + new ISatelliteCapabilitiesCallback.Stub() { + @Override + public void onSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) { + logd("onSatelliteCapabilitiesChanged: " + capabilities); + try { + satelliteCapabilities[0] = capabilities; + semaphore.release(); + } catch (Exception ex) { + loge("onSatelliteCapabilitiesChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + + int errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode); + + setUpResponseForRequestIsSatelliteSupported(false, + SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED); + errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED); + errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID, + callback); + assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode); + + SatelliteCapabilities expectedCapabilities = mSatelliteCapabilities; + sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 0, "testRegisterForSatelliteCapabilitiesChanged")); } private void resetSatelliteControllerUTEnabledState() { logd("resetSatelliteControllerUTEnabledState"); - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE); doNothing().when(mMockSatelliteModemInterface) .setSatelliteServicePackageName(anyString()); mSatelliteControllerUT.setSatelliteServicePackageName("TestSatelliteService"); processAllMessages(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); sendProvisionedStateChangedEvent(true, null); processAllMessages(); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); } private void resetSatelliteControllerUT() { @@ -1611,7 +2571,7 @@ public class SatelliteControllerTest extends TelephonyTest { processAllMessages(); // Reset all cached states - setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE); doNothing().when(mMockSatelliteModemInterface) .setSatelliteServicePackageName(anyString()); mSatelliteControllerUT.setSatelliteServicePackageName("TestSatelliteService"); @@ -1620,11 +2580,11 @@ public class SatelliteControllerTest extends TelephonyTest { private void resetSatelliteControllerUTToSupportedAndProvisionedState() { resetSatelliteControllerUT(); - setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS); + verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS); sendProvisionedStateChangedEvent(true, null); processAllMessages(); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS); } private void resetSatelliteControllerUTToOffAndProvisionedState() { @@ -1632,7 +2592,7 @@ public class SatelliteControllerTest extends TelephonyTest { // Clean up pending resources and move satellite controller to OFF state. sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_UNAVAILABLE, null); processAllMessages(); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS); } private void resetSatelliteControllerUTToOnAndProvisionedState() { @@ -1640,17 +2600,17 @@ public class SatelliteControllerTest extends TelephonyTest { setRadioPower(true); processAllMessages(); - setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); - verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS); } private void setUpResponseForRequestIsSatelliteEnabled(boolean isSatelliteEnabled, - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1661,8 +2621,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForRequestIsSatelliteSupported( - boolean isSatelliteSupported, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + boolean isSatelliteSupported, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1673,8 +2633,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForRequestIsSatelliteAllowedForCurrentLocation( - boolean isSatelliteAllowed, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + boolean isSatelliteAllowed, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1686,8 +2646,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1699,10 +2659,10 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForRequestTimeForNextSatelliteVisibility( - int satelliteVisibilityTime, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + int satelliteVisibilityTime, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); - int[] visibilityTime = new int[] {satelliteVisibilityTime}; + int[] visibilityTime = new int[]{satelliteVisibilityTime}; doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, visibilityTime, exception); @@ -1713,8 +2673,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpNullResponseForRequestTimeForNextSatelliteVisibility( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1726,10 +2686,10 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForRequestIsSatelliteProvisioned( - boolean isSatelliteProvisioned, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + boolean isSatelliteProvisioned, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); - int[] provisioned = new int[] {isSatelliteProvisioned ? 1 : 0}; + int[] provisioned = new int[]{isSatelliteProvisioned ? 1 : 0}; doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, provisioned, exception); @@ -1739,8 +2699,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForRequestSatelliteEnabled( - boolean enabled, boolean demoMode, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + boolean enabled, boolean demoMode, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { if (exception == null && !enabled) { @@ -1754,14 +2714,27 @@ public class SatelliteControllerTest extends TelephonyTest { .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class)); } + private void setUpResponseForRequestSetSatelliteEnabledForCarrier( + boolean enabled, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[2]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestSetSatelliteEnabledForCarrier(anyInt(), eq(enabled), any(Message.class)); + } + private void setUpNoResponseForRequestSatelliteEnabled(boolean enabled, boolean demoMode) { doNothing().when(mMockSatelliteModemInterface) .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class)); } private void setUpResponseForProvisionSatelliteService( - String token, byte[] provisionData, @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + String token, byte[] provisionData, @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[2]; @@ -1778,8 +2751,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForDeprovisionSatelliteService(String token, - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[1]; @@ -1792,8 +2765,8 @@ public class SatelliteControllerTest extends TelephonyTest { private void setUpResponseForRequestSatelliteCapabilities( SatelliteCapabilities satelliteCapabilities, - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1803,6 +2776,20 @@ public class SatelliteControllerTest extends TelephonyTest { }).when(mMockSatelliteModemInterface).requestSatelliteCapabilities(any(Message.class)); } + private void setUpResponseForRequestNtnSignalStrength( + @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel, + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, new NtnSignalStrength(ntnSignalStrengthLevel), + exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestNtnSignalStrength(any(Message.class)); + } + private boolean waitForForEvents( Semaphore semaphore, int expectedNumberOfEvents, String caller) { for (int i = 0; i < expectedNumberOfEvents; i++) { @@ -1820,8 +2807,8 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpNullResponseForRequestSatelliteCapabilities( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; @@ -1832,29 +2819,51 @@ public class SatelliteControllerTest extends TelephonyTest { } private void setUpResponseForStartSatelliteTransmissionUpdates( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, null, exception); message.sendToTarget(); return null; - }).when(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class), - any()); + }).when(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class)); } private void setUpResponseForStopSatelliteTransmissionUpdates( - @SatelliteManager.SatelliteError int error) { - SatelliteException exception = (error == SATELLITE_ERROR_NONE) + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) ? null : new SatelliteException(error); doAnswer(invocation -> { Message message = (Message) invocation.getArguments()[0]; AsyncResult.forMessage(message, null, exception); message.sendToTarget(); return null; - }).when(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class), - any()); + }).when(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class)); + } + + private void setUpResponseForStartSendingNtnSignalStrength( + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).startSendingNtnSignalStrength(any(Message.class)); + } + + private void setUpResponseForStopSendingNtnSignalStrength( + @SatelliteManager.SatelliteResult int error) { + SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).stopSendingNtnSignalStrength(any(Message.class)); } private boolean waitForRequestIsSatelliteSupportedResult(int expectedNumberOfEvents) { @@ -1967,6 +2976,22 @@ public class SatelliteControllerTest extends TelephonyTest { return true; } + private boolean waitForRequestNtnSignalStrengthResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mRequestNtnSignalStrengthSemaphore.tryAcquire(TIMEOUT, + TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestNtnSignalStrength() callback"); + return false; + } + } catch (Exception ex) { + loge("requestNtnSignalStrength: Got exception=" + ex); + return false; + } + } + return true; + } + private boolean waitForIIntegerConsumerResult(int expectedNumberOfEvents) { for (int i = 0; i < expectedNumberOfEvents; i++) { try { @@ -2010,6 +3035,17 @@ public class SatelliteControllerTest extends TelephonyTest { assertEquals(provisioned, mQueriedIsSatelliteProvisioned); } + private void verifyRequestNtnSignalStrength( + @NtnSignalStrength.NtnSignalStrengthLevel int signalStrengthLevel, + int expectedErrorCode) { + mRequestNtnSignalStrengthSemaphore.drainPermits(); + mSatelliteControllerUT.requestNtnSignalStrength(SUB_ID, mRequestNtnSignalStrengthReceiver); + processAllMessages(); + assertTrue(waitForRequestNtnSignalStrengthResult(1)); + assertEquals(expectedErrorCode, mQueriedNtnSignalStrengthResultCode); + assertEquals(signalStrengthLevel, mQueriedNtnSignalStrengthLevel); + } + private void sendProvisionedStateChangedEvent(boolean provisioned, Throwable exception) { Message msg = mSatelliteControllerUT.obtainMessage( 26 /* EVENT_SATELLITE_PROVISION_STATE_CHANGED */); @@ -2024,10 +3060,65 @@ public class SatelliteControllerTest extends TelephonyTest { msg.sendToTarget(); } + private void sendNtnSignalStrengthChangedEvent( + @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel, + Throwable exception) { + Message msg = mSatelliteControllerUT.obtainMessage( + 34 /* EVENT_NTN_SIGNAL_STRENGTH_CHANGED */); + msg.obj = new AsyncResult(null, new NtnSignalStrength(ntnSignalStrengthLevel), + exception); + msg.sendToTarget(); + } + + private void sendCmdStartSendingNtnSignalStrengthChangedEvent(boolean shouldReport) { + Message msg = mSatelliteControllerUT.obtainMessage( + 35 /* CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING */); + msg.obj = new AsyncResult(null, shouldReport, null); + msg.sendToTarget(); + } + + private void sendStartSendingNtnSignalStrengthChangedEvent( + @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel, + Throwable exception) { + Message msg = mSatelliteControllerUT.obtainMessage( + 36 /* EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE */); + msg.obj = new AsyncResult(null, new NtnSignalStrength(ntnSignalStrengthLevel), + exception); + msg.sendToTarget(); + } + + private void sendServiceStateChangedEvent() { + mSatelliteControllerUT.obtainMessage(37 /* EVENT_SERVICE_STATE_CHANGED */).sendToTarget(); + } + + private void sendSatelliteCapabilitiesChangedEvent(SatelliteCapabilities capabilities, + Throwable exception) { + Message msg = mSatelliteControllerUT.obtainMessage( + 38 /* EVENT_SATELLITE_CAPABILITIES_CHANGED */); + msg.obj = new AsyncResult(null, capabilities, exception); + msg.sendToTarget(); + } + private void setRadioPower(boolean on) { mSimulatedCommands.setRadioPower(on, false, false, null); } + private void verifyRegisterForNtnSignalStrengthChanged(int subId, + INtnSignalStrengthCallback callback, int expectedError) { + if (expectedError == SATELLITE_RESULT_SUCCESS) { + try { + mSatelliteControllerUT.registerForNtnSignalStrengthChanged(subId, callback); + } catch (RemoteException ex) { + throw new AssertionError(); + } + } else { + ServiceSpecificException ex = assertThrows(ServiceSpecificException.class, + () -> mSatelliteControllerUT.registerForNtnSignalStrengthChanged(subId, + callback)); + assertEquals(expectedError, ex.errorCode); + } + } + private static void loge(String message) { Rlog.e(TAG, message); } @@ -2176,10 +3267,12 @@ public class SatelliteControllerTest extends TelephonyTest { private static class TestSatelliteController extends SatelliteController { public boolean setSettingsKeyForSatelliteModeCalled = false; public boolean allRadiosDisabled = true; + public long elapsedRealtime = 0; public int satelliteModeSettingValue = SATELLITE_MODE_ENABLED_FALSE; - TestSatelliteController(Context context, Looper looper) { - super(context, looper); + TestSatelliteController( + Context context, Looper looper, @NonNull FeatureFlags featureFlags) { + super(context, looper, featureFlags); logd("Constructing TestSatelliteController"); } @@ -2199,5 +3292,17 @@ public class SatelliteControllerTest extends TelephonyTest { protected boolean areAllRadiosDisabled() { return allRadiosDisabled; } + + @Override + protected int getSupportedNtnRadioTechnology() { + int ntRadioTechnology = super.getSupportedNtnRadioTechnology(); + logd("getCurrentNtnRadioTechnology: val=" + ntRadioTechnology); + return ntRadioTechnology; + } + + @Override + protected long getElapsedRealtime() { + return elapsedRealtime; + } } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 5e1129747e..589f32b1fe 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -16,6 +16,11 @@ package com.android.internal.telephony.satellite; +import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; +import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS; +import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -26,30 +31,35 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; +import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.res.Resources; -import android.os.AsyncResult; import android.os.Bundle; import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; -import android.telecom.Call; import android.telecom.Connection; import android.telephony.BinderCacheManager; -import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.telephony.ims.RegistrationManager; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.text.TextUtils; import android.util.Log; import com.android.ims.ImsException; import com.android.ims.ImsManager; +import com.android.internal.R; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import org.junit.After; import org.junit.Before; @@ -59,8 +69,10 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; @@ -74,48 +86,56 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private static final String TAG = "SatelliteSOSMessageRecommenderTest"; private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500; private static final int PHONE_ID = 0; + private static final int PHONE_ID2 = 1; private static final String CALL_ID = "CALL_ID"; private static final String WRONG_CALL_ID = "WRONG_CALL_ID"; + private static final String DEFAULT_SATELLITE_MESSAGING_PACKAGE = "android.com.google.default"; + private static final String DEFAULT_SATELLITE_MESSAGING_CLASS = + "android.com.google.default.SmsMmsApp"; + private static final String DEFAULT_HANDOVER_INTENT_ACTION = + "android.com.vendor.action.EMERGENCY_MESSAGING"; private TestSatelliteController mTestSatelliteController; private TestImsManager mTestImsManager; - - @Mock - private Context mMockContext; @Mock private Resources mResources; @Mock private ImsManager.MmTelFeatureConnectionFactory mMmTelFeatureConnectionFactory; + @Mock + private FeatureFlags mFeatureFlags; private TestConnection mTestConnection; private TestSOSMessageRecommender mTestSOSMessageRecommender; + private ServiceState mServiceState2; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); - when(mMockContext.getResources()).thenReturn(mResources); - when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getString(R.string.config_satellite_service_package)) .thenReturn(""); - when(mMockContext.getSystemServiceName(CarrierConfigManager.class)) - .thenReturn("CarrierConfigManager"); - when(mMockContext.getSystemService(CarrierConfigManager.class)) - .thenReturn(mCarrierConfigManager); - when(mMockContext.getSystemServiceName(SubscriptionManager.class)) - .thenReturn("SubscriptionManager"); - when(mMockContext.getSystemService(SubscriptionManager.class)) - .thenReturn(mSubscriptionManager); - mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.myLooper()); + when(mResources.getString(R.string.config_satellite_emergency_handover_intent_action)) + .thenReturn(DEFAULT_HANDOVER_INTENT_ACTION); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); + mTestSatelliteController = new TestSatelliteController(mContext, + Looper.myLooper(), mFeatureFlags); mTestImsManager = new TestImsManager( - mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); + mContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); + mPhones = new Phone[] {mPhone, mPhone2}; + replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); + mServiceState2 = Mockito.mock(ServiceState.class); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), + when(mPhone.getPhoneId()).thenReturn(PHONE_ID); + when(mPhone2.getServiceState()).thenReturn(mServiceState2); + when(mPhone2.getPhoneId()).thenReturn(PHONE_ID2); + mTestSOSMessageRecommender = new TestSOSMessageRecommender(mContext, Looper.myLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); + when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); when(mPhone.isImsRegistered()).thenReturn(false); + when(mPhone2.isImsRegistered()).thenReturn(false); } @After @@ -124,18 +144,103 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } @Test - public void testTimeoutBeforeEmergencyCallEnd() { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + public void testTimeoutBeforeEmergencyCallEnd_T911() { + testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, + DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS, + DEFAULT_HANDOVER_INTENT_ACTION); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd_SOS_WithValidHandoverAppConfigured() { + String satelliteHandoverApp = + "android.com.vendor.message;android.com.vendor.message.SmsApp"; + when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app)) + .thenReturn(satelliteHandoverApp); + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false); + testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, + "android.com.vendor.message", "android.com.vendor.message.SmsApp", + DEFAULT_HANDOVER_INTENT_ACTION); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd_SOS_WithInValidHandoverAppConfigured() { + String satelliteHandoverApp = + "android.com.vendor.message;android.com.vendor.message.SmsApp;abc"; + when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app)) + .thenReturn(satelliteHandoverApp); + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false); + testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "", + DEFAULT_HANDOVER_INTENT_ACTION); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd_SOS_WithoutHandoverAppConfigured() { + when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app)) + .thenReturn(""); + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false); + testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "", + DEFAULT_HANDOVER_INTENT_ACTION); + } + + private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType, + String expectedPackageName, String expectedClassName, String expectedAction) { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); // Wait for the timeout to expires moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); processAllMessages(); + if (TextUtils.isEmpty(expectedPackageName) || TextUtils.isEmpty(expectedClassName)) { + assertTrue(mTestConnection.isEventWithoutLaunchIntentSent( + TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, expectedHandoverType)); + } else { + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + expectedHandoverType, expectedPackageName, expectedClassName, expectedAction)); + } + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd_EventDisplayEmergencyMessageNotSent() { + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false); + mTestSatelliteController.setIsSatelliteViaOemProvisioned(false); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); + processAllMessages(); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); - assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + // Wait for the timeout to expires + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd_T911_FromNotConnectedToConnected() { + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); + processAllMessages(); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); + + mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true); + // Wait for the timeout to expires + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, + DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS, + DEFAULT_HANDOVER_INTENT_ACTION)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); } @Test @@ -150,22 +255,34 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); - mTestImsManager.sendImsRegistrationStateChangedEvent(true); + when(mPhone.isImsRegistered()).thenReturn(true); + mTestImsManager.sendImsRegistrationStateChangedEvent(0, true); processAllMessages(); - assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); + + when(mPhone.isImsRegistered()).thenReturn(false); + when(mPhone2.isImsRegistered()).thenReturn(true); + mTestImsManager.sendImsRegistrationStateChangedEvent(1, true); + processAllMessages(); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); - mTestImsManager.sendImsRegistrationStateChangedEvent(false); + when(mPhone2.isImsRegistered()).thenReturn(false); + mTestImsManager.sendImsRegistrationStateChangedEvent(1, false); processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -173,19 +290,23 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); processAllMessages(); - assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE, + DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); } @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); @@ -193,13 +314,15 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); + assertRegisterForStateChangedEventsTriggered(mPhone, 2, 4, 2); + assertRegisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2); mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); @@ -208,57 +331,44 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); processAllMessages(); - assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE, + DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); + assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 4, 2); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2); } @Test public void testEmergencyCallRedialBeforeTimeout() { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); - Phone newPhone = Mockito.mock(Phone.class); - when(newPhone.getServiceState()).thenReturn(mServiceState); - when(newPhone.isImsRegistered()).thenReturn(false); - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - /** - * Since {@link SatelliteSOSMessageRecommender} always uses - * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when registering for provision state - * changed events with {@link SatelliteController}, registerForProvisionCount does - * not depend on Phone. - * <p> - * Since we use a single mocked ImsManager instance, registerForImsCount does not depend on - * Phone. - */ - assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); // Wait for the timeout to expires moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); processAllMessages(); - assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); - /** - * Since {@link SatelliteSOSMessageRecommender} always uses - * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when unregistering for provision - * state changed events with {@link SatelliteController}, unregisterForProvisionCount does - * not depend on Phone. - * <p> - * Since we use a single mocked ImsManager instance, unregisterForImsCount does not depend - * on Phone. - */ - assertUnregisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE, + DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); } @Test @@ -287,50 +397,55 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); processAllMessages(); - assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); } @Test public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); /** - * We should have registered for the state change events abd started the timer when + * We should have registered for the state change events and started the timer when * receiving the event onEmergencyCallStarted. After getting the callback for the result of * the request requestIsSatelliteCommunicationAllowedForCurrentLocation, the resources * should be cleaned up. */ assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); } @Test public void testOnEmergencyCallStarted() { SatelliteController satelliteController = new SatelliteController( - mMockContext, Looper.myLooper()); + mContext, Looper.myLooper(), mFeatureFlags); TestSOSMessageRecommender testSOSMessageRecommender = new TestSOSMessageRecommender( + mContext, Looper.myLooper(), satelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertFalse(testSOSMessageRecommender.isTimerStarted()); @@ -339,51 +454,68 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); processAllMessages(); - assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); } private void testCellularServiceStateChangedBeforeTimeout( @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { - mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection); processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); - assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); - mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); + when(mServiceState.getState()).thenReturn(availableServiceState); + mTestSOSMessageRecommender.sendServiceStateChangedEvent(); processAllMessages(); - - assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 0, 0, 0); - mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); + when(mServiceState.getState()).thenReturn(unavailableServiceState); + when(mServiceState2.getState()).thenReturn(availableServiceState); + mTestSOSMessageRecommender.sendServiceStateChangedEvent(); + processAllMessages(); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + + when(mServiceState2.getState()).thenReturn(unavailableServiceState); + mTestSOSMessageRecommender.sendServiceStateChangedEvent(); processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); // Wait for the timeout to expires moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); processAllMessages(); - assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); - assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, + EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE, + DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); } private void assertRegisterForStateChangedEventsTriggered( @@ -412,8 +544,9 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private boolean mIsSatelliteProvisioned = true; + private boolean mIsSatelliteViaOemProvisioned = true; private boolean mIsSatelliteCommunicationAllowed = true; + private boolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = true; /** * Create a SatelliteController to act as a backend service of @@ -421,30 +554,31 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { * * @param context The Context for the SatelliteController. */ - protected TestSatelliteController(Context context, Looper looper) { - super(context, looper); + protected TestSatelliteController( + Context context, Looper looper, FeatureFlags featureFlags) { + super(context, looper, featureFlags); mProvisionStateChangedCallbacks = new HashMap<>(); } @Override - public Boolean isSatelliteProvisioned() { - return mIsSatelliteProvisioned; + public Boolean isSatelliteViaOemProvisioned() { + return mIsSatelliteViaOemProvisioned; } @Override - public boolean isSatelliteSupported() { + public boolean isSatelliteSupportedViaOem() { return true; } @Override - @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged( + @SatelliteManager.SatelliteResult public int registerForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { mRegisterForSatelliteProvisionStateChangedCalls++; Set<ISatelliteProvisionStateCallback> perSubscriptionCallbacks = mProvisionStateChangedCallbacks.getOrDefault(subId, new HashSet<>()); perSubscriptionCallbacks.add(callback); mProvisionStateChangedCallbacks.put(subId, perSubscriptionCallbacks); - return SatelliteManager.SATELLITE_ERROR_NONE; + return SatelliteManager.SATELLITE_RESULT_SUCCESS; } @Override @@ -464,13 +598,28 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, mIsSatelliteCommunicationAllowed); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle); + } + + @Override + public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() { + return mIsSatelliteConnectedViaCarrierWithinHysteresisTime; + } + + @Override + protected int getEnforcedEmergencyCallToSatelliteHandoverType() { + return INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE; } public void setIsSatelliteCommunicationAllowed(boolean allowed) { mIsSatelliteCommunicationAllowed = allowed; } + public void setSatelliteConnectedViaCarrierWithinHysteresisTime( + boolean connectedViaCarrier) { + mIsSatelliteConnectedViaCarrierWithinHysteresisTime = connectedViaCarrier; + } + public int getRegisterForSatelliteProvisionStateChangedCalls() { return mRegisterForSatelliteProvisionStateChangedCalls; } @@ -479,8 +628,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { return mUnregisterForSatelliteProvisionStateChangedCalls; } + public void setIsSatelliteViaOemProvisioned(boolean provisioned) { + mIsSatelliteViaOemProvisioned = provisioned; + } + public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mIsSatelliteProvisioned = provisioned; + mIsSatelliteViaOemProvisioned = provisioned; Set<ISatelliteProvisionStateCallback> perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { @@ -497,7 +650,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private static class TestImsManager extends ImsManager { - private final Set<RegistrationManager.RegistrationCallback> mCallbacks; + private final List<RegistrationManager.RegistrationCallback> mCallbacks; private int mAddRegistrationCallbackCalls = 0; private int mRemoveRegistrationListenerCalls = 0; @@ -508,7 +661,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManagerProxy subManagerProxy, SettingsProxy settingsProxy, BinderCacheManager binderCacheManager) { super(context, phoneId, factory, subManagerProxy, settingsProxy, binderCacheManager); - mCallbacks = new HashSet<>(); + mCallbacks = new ArrayList<>(); } @Override @@ -525,7 +678,9 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } callback.setExecutor(executor); - mCallbacks.add(callback); + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + } } @Override @@ -546,20 +701,24 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { return mRemoveRegistrationListenerCalls; } - public void sendImsRegistrationStateChangedEvent(boolean registered) { + public void sendImsRegistrationStateChangedEvent(int callbackIndex, boolean registered) { + if (callbackIndex < 0 || callbackIndex >= mCallbacks.size()) { + throw new IndexOutOfBoundsException("sendImsRegistrationStateChangedEvent: invalid" + + "callbackIndex=" + callbackIndex + + ", mCallbacks.size=" + mCallbacks.size()); + } + RegistrationManager.RegistrationCallback callback = mCallbacks.get(callbackIndex); if (registered) { - for (RegistrationManager.RegistrationCallback callback : mCallbacks) { - callback.onRegistered(null); - } + callback.onRegistered(null); } else { - for (RegistrationManager.RegistrationCallback callback : mCallbacks) { - callback.onUnregistered(null); - } + callback.onUnregistered(null); } } } private static class TestSOSMessageRecommender extends SatelliteSOSMessageRecommender { + private ComponentName mSmsAppComponent = new ComponentName( + DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS); /** * Create an instance of SatelliteSOSMessageRecommender. @@ -571,9 +730,15 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { * null only in unit tests. * @param timeoutMillis The timeout duration of the timer. */ - TestSOSMessageRecommender(Looper looper, SatelliteController satelliteController, - ImsManager imsManager, long timeoutMillis) { - super(looper, satelliteController, imsManager, timeoutMillis); + TestSOSMessageRecommender(Context context, Looper looper, + SatelliteController satelliteController, ImsManager imsManager, + long timeoutMillis) { + super(context, looper, satelliteController, imsManager, timeoutMillis); + } + + @Override + protected ComponentName getDefaultSmsApp() { + return mSmsAppComponent; } public boolean isTimerStarted() { @@ -584,28 +749,66 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { return mCountOfTimerStarted; } - public void sendServiceStateChangedEvent(@ServiceState.RegState int state) { - ServiceState serviceState = new ServiceState(); - serviceState.setState(state); - sendMessage(obtainMessage(EVENT_CELLULAR_SERVICE_STATE_CHANGED, - new AsyncResult(null, serviceState, null))); + public void sendServiceStateChangedEvent() { + sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED)); } } private static class TestConnection extends Connection { - private final Set<String> mSentEvents; + private String mSentEvent = null; + private Bundle mExtras = null; TestConnection(String callId) { setTelecomCallId(callId); - mSentEvents = new HashSet<>(); } @Override public void sendConnectionEvent(String event, Bundle extras) { - mSentEvents.add(event); + mSentEvent = event; + mExtras = extras; + } + + public boolean isEventSent(String event, int handoverType, String packageName, + String className, String action) { + if (mSentEvent == null || mExtras == null) { + return false; + } + + PendingIntent pendingIntent = mExtras.getParcelable( + EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT, PendingIntent.class); + Intent intent = pendingIntent.getIntent(); + if (!TextUtils.equals(event, mSentEvent) || handoverType != mExtras.getInt( + EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE) + || !TextUtils.equals(packageName, intent.getComponent().getPackageName()) + || !TextUtils.equals(className, intent.getComponent().getClassName()) + || !TextUtils.equals(action, intent.getAction())) { + return false; + } + return true; + } + + public boolean isEventWithoutLaunchIntentSent(String event, int handoverType) { + if (mSentEvent == null || mExtras == null) { + return false; + } + + PendingIntent pendingIntent = mExtras.getParcelable( + EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT, PendingIntent.class); + if (!TextUtils.equals(event, mSentEvent) || handoverType != mExtras.getInt( + EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE) || pendingIntent != null) { + return false; + } + + return true; } public boolean isEventSent(String event) { - return mSentEvents.contains(event); + if (mSentEvent == null) { + return false; + } + if (!TextUtils.equals(event, mSentEvent)) { + return false; + } + return true; } } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java index ba1fb9ea39..28874df23b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java @@ -17,7 +17,6 @@ package com.android.internal.telephony.satellite; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.os.PersistableBundle; @@ -33,8 +32,7 @@ import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -57,58 +55,6 @@ public class SatelliteServiceUtilsTest extends TelephonyTest { } @Test - public void testParseSupportedSatelliteServicesFromStringArray() { - // Parse correct format input string - int[] expectedServices1 = {2, 3}; - int[] expectedServices2 = {3}; - String[] supportedServicesStrArr1 = {"10011:2,3", "10112:3"}; - Map<String, Set<Integer>> supportedServiceMap = - SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServicesStrArr1); - - assertTrue(supportedServiceMap.containsKey("10011")); - Set<Integer> supportedServices = supportedServiceMap.get("10011"); - assertTrue(Arrays.equals(expectedServices1, - supportedServices.stream() - .mapToInt(Integer::intValue) - .toArray())); - - assertTrue(supportedServiceMap.containsKey("10112")); - supportedServices = supportedServiceMap.get("10112"); - assertTrue(Arrays.equals(expectedServices2, - supportedServices.stream() - .mapToInt(Integer::intValue) - .toArray())); - - // Parse correct mixed with incorrect format input string - String[] supportedServicesStrArr2 = {"10011:2,3,1xy", "10112:3,70", "10012:"}; - supportedServiceMap = SatelliteServiceUtils.parseSupportedSatelliteServices( - supportedServicesStrArr2); - - assertTrue(supportedServiceMap.containsKey("10011")); - supportedServices = supportedServiceMap.get("10011"); - assertTrue(Arrays.equals(expectedServices1, - supportedServices.stream() - .mapToInt(Integer::intValue) - .toArray())); - - assertTrue(supportedServiceMap.containsKey("10112")); - supportedServices = supportedServiceMap.get("10112"); - assertTrue(Arrays.equals(expectedServices2, - supportedServices.stream() - .mapToInt(Integer::intValue) - .toArray())); - - assertTrue(supportedServiceMap.containsKey("10012")); - assertTrue(supportedServiceMap.get("10012").isEmpty()); - - // Parse an empty input string - String[] supportedServicesStrArr3 = {}; - supportedServiceMap = SatelliteServiceUtils.parseSupportedSatelliteServices( - supportedServicesStrArr3); - assertTrue(supportedServiceMap.isEmpty()); - } - - @Test public void testParseSupportedSatelliteServicesFromPersistableBundle() { PersistableBundle supportedServicesBundle = new PersistableBundle(); String plmn1 = "10101"; @@ -153,46 +99,11 @@ public class SatelliteServiceUtilsTest extends TelephonyTest { } @Test - public void testMergeSupportedSatelliteServices() { - String plmn1 = "00101"; - String plmn2 = "00102"; - String plmn3 = "00103"; - - Integer[] providerSupportedServicesForPlmn1 = {1, 2, 3}; - Integer[] providerSupportedServicesForPlmn2 = {3, 4}; - Map<String, Set<Integer>> providerSupportedServicesMap = new HashMap<>(); - providerSupportedServicesMap.put( - plmn1, new HashSet<>(Arrays.asList(providerSupportedServicesForPlmn1))); - providerSupportedServicesMap.put( - plmn2, new HashSet<>(Arrays.asList(providerSupportedServicesForPlmn2))); - - Integer[] carrierSupportedServicesForPlmn2 = {3}; - Integer[] carrierSupportedServicesForPlmn3 = {1, 3, 4}; - Map<String, Set<Integer>> carrierSupportedServicesMap = new HashMap<>(); - carrierSupportedServicesMap.put( - plmn2, new HashSet<>(Arrays.asList(carrierSupportedServicesForPlmn2))); - carrierSupportedServicesMap.put( - plmn3, new HashSet<>(Arrays.asList(carrierSupportedServicesForPlmn3))); - - // {@code plmn1} is present in only provider support services. - int[] expectedSupportedServicesForPlmn1 = {1, 2, 3}; - // Intersection of {3,4} and {3}. - int[] expectedSupportedServicesForPlmn2 = {3}; - Map<String, Set<Integer>> supportedServicesMap = - SatelliteServiceUtils.mergeSupportedSatelliteServices( - providerSupportedServicesMap, carrierSupportedServicesMap); - - assertEquals(2, supportedServicesMap.size()); - assertTrue(supportedServicesMap.containsKey(plmn1)); - assertTrue(supportedServicesMap.containsKey(plmn2)); - assertFalse(supportedServicesMap.containsKey(plmn3)); - assertTrue(Arrays.equals(expectedSupportedServicesForPlmn1, - supportedServicesMap.get(plmn1).stream() - .mapToInt(Integer::intValue) - .toArray())); - assertTrue(Arrays.equals(expectedSupportedServicesForPlmn2, - supportedServicesMap.get(plmn2).stream() - .mapToInt(Integer::intValue) - .toArray())); + public void testMergeStrLists() { + List<String> l1 = Arrays.asList("1", "2", "2"); + List<String> l2 = Arrays.asList("1", "3", "3"); + List<String> expectedMergedList = Arrays.asList("1", "2", "3"); + List<String> mergedList = SatelliteServiceUtils.mergeStrLists(l1, l2); + assertEquals(expectedMergedList, mergedList); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 3ccf512211..50c6c24dba 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -21,15 +21,21 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TR import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Resources; import android.os.Looper; import android.os.Message; import android.telephony.satellite.ISatelliteStateCallback; @@ -57,33 +63,48 @@ import java.util.concurrent.atomic.AtomicInteger; @TestableLooper.RunWithLooper public class SatelliteSessionControllerTest extends TelephonyTest { private static final String TAG = "SatelliteSessionControllerTest"; - private static final long TEST_SATELLITE_STAY_AT_LISTENING_MILLIS = 200; - private static final long EVENT_PROCESSING_TIME_MILLIS = 100; + private static final int TEST_SATELLITE_TIMEOUT_MILLIS = 200; + private static final int EVENT_PROCESSING_TIME_MILLIS = 100; private static final String STATE_UNAVAILABLE = "UnavailableState"; private static final String STATE_POWER_OFF = "PowerOffState"; private static final String STATE_IDLE = "IdleState"; private static final String STATE_TRANSFERRING = "TransferringState"; private static final String STATE_LISTENING = "ListeningState"; + private static final String STATE_NOT_CONNECTED = "NotConnectedState"; + private static final String STATE_CONNECTED = "ConnectedState"; private TestSatelliteModemInterface mSatelliteModemInterface; private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; - @Mock - private SatelliteController mSatelliteController; + @Mock private SatelliteController mMockSatelliteController; + @Mock private DatagramReceiver mMockDatagramReceiver; + @Mock private DatagramDispatcher mMockDatagramDispatcher; + @Mock private DatagramController mMockDatagramController; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); + replaceInstance(DatagramReceiver.class, "sInstance", null, + mMockDatagramReceiver); + replaceInstance(DatagramDispatcher.class, "sInstance", null, + mMockDatagramDispatcher); + replaceInstance(SatelliteController.class, "sInstance", null, + mMockSatelliteController); + replaceInstance(DatagramController.class, "sInstance", null, + mMockDatagramController); + + Resources resources = mContext.getResources(); + when(resources.getInteger(anyInt())).thenReturn(TEST_SATELLITE_TIMEOUT_MILLIS); + + when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(false); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, mSatelliteController, Looper.myLooper()); + mContext, mMockSatelliteController, Looper.myLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.myLooper(), true, mSatelliteModemInterface, - TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, - TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + Looper.myLooper(), true, mSatelliteModemInterface); processAllMessages(); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); @@ -105,8 +126,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, - mSatelliteModemInterface, 100, 100); + mContext, Looper.myLooper(), false, mSatelliteModemInterface); assertNotNull(sessionController1); processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); @@ -115,8 +135,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), true, - mSatelliteModemInterface, 100, 100); + mContext, Looper.myLooper(), true, mSatelliteModemInterface); assertNotNull(sessionController2); processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); @@ -129,8 +148,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, - mSatelliteModemInterface, 100, 100); + mContext, Looper.myLooper(), false, mSatelliteModemInterface); assertNotNull(sessionController); processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); @@ -305,7 +323,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); processAllMessages(); // SatelliteSessionController should move to IDLE state after timeout @@ -384,9 +402,390 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); } + @Test + public void testStateTransitionForNbIot() { + when(mMockSatelliteController.isSatelliteAttachRequired()).thenReturn(true); + + /** + * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. + */ + assertNotNull(mTestSatelliteSessionController); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + setupDatagramTransferringState(false); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state after the satellite modem + // is powered on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + clearInvocations(mMockDatagramController); + + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + // SatelliteSessionController should stay at NOT_CONNECTED state. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + setupDatagramTransferringState(true); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); + + // SatelliteSessionController should move back to POWER_OFF state. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + clearInvocations(mMockDatagramController); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state after radio is turned on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + clearInvocations(mMockDatagramController); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // The datagram sending event should be ignored. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + // Satellite modem is connected to a satellite network. + mTestSatelliteSessionController.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + clearInvocations(mMockDatagramController); + + // Sending datagrams failed + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Start sending datagrams again + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + clearInvocations(mMockDatagramController); + + // Sending datagrams is successful and done. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Start receiving datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + clearInvocations(mMockDatagramController); + + // Receiving datagrams is successful and done. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Wait for timeout + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + + // SatelliteSessionController should move to IDLE state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + clearInvocations(mMockDatagramController); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + clearInvocations(mMockDatagramController); + + // Satellite modem is connected to a satellite network. + mTestSatelliteSessionController.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Satellite modem is disconnected from the satellite network. + mTestSatelliteSessionController.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + clearInvocations(mMockDatagramController); + + // Satellite modem is connected to a satellite network. + mTestSatelliteSessionController.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + clearInvocations(mMockDatagramController); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); + + // SatelliteSessionController should move to POWER_OFF state. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + clearInvocations(mMockDatagramController); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state after the satellite modem + // is powered on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + verify(mMockDatagramController).onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + clearInvocations(mMockDatagramController); + + // Satellite modem is connected to a satellite network. + mTestSatelliteSessionController.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + processAllMessages(); + + // SatelliteSessionController should move to CONNECTED state + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED); + assertEquals(STATE_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + // Wait for timeout + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + + // SatelliteSessionController should move to IDLE state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + + // Set up error response for the request to disable cellular scanning + mSatelliteModemInterface.setErrorCode(SatelliteManager.SATELLITE_RESULT_MODEM_ERROR); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + + // SatelliteSessionController should stay at IDLE state because it failed to disable + // cellular scanning. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + + mSatelliteModemInterface.setErrorCode(SatelliteManager.SATELLITE_RESULT_SUCCESS); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); + + // SatelliteSessionController should move to POWER_OFF + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state after the satellite modem + // is powered on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + + // SatelliteSessionController should move to IDLE state because NB-IOT inactivity timer has + // timed out. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); + + // SatelliteSessionController should move to POWER_OFF + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); + + // SatelliteSessionController should move to NOT_CONNECTED state after the satellite modem + // is powered on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + // Start sending datagrams and the NB-IOT inactivity timer should be stopped. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + + // SatelliteSessionController should stay at NOT_CONNECTED state because. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_NOT_CONNECTED, mTestSatelliteSessionController.getCurrentStateName()); + + // Transferring datagram failed because satellite failed to connect to a satellite network. + // The NB-IOT inactivity timer should be started. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); + assertTrue(mTestSatelliteSessionController.isNbIotInactivityTimerStarted()); + + moveTimeForward(TEST_SATELLITE_TIMEOUT_MILLIS); + processAllMessages(); + + // SatelliteSessionController should move to IDLE state because NB-IOT inactivity timer has + // timed out. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + } + + private void setupDatagramTransferringState(boolean isTransferring) { + when(mMockDatagramController.isSendingInIdleState()).thenReturn(isTransferring); + when(mMockDatagramController.isPollingInIdleState()).thenReturn(isTransferring); + } + private static class TestSatelliteModemInterface extends SatelliteModemInterface { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); + @SatelliteManager.SatelliteResult + private int mErrorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS; TestSatelliteModemInterface(@NonNull Context context, SatelliteController satelliteController, @NonNull Looper looper) { @@ -411,6 +810,14 @@ public class SatelliteSessionControllerTest extends TelephonyTest { else mListeningDisabledCount.incrementAndGet(); } + @Override + public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled, + @Nullable Message message) { + if (message != null) { + sendMessageWithResult(message, null, mErrorCode); + } + } + public int getListeningEnabledCount() { return mListeningEnabledCount.get(); } @@ -418,25 +825,29 @@ public class SatelliteSessionControllerTest extends TelephonyTest { public int getListeningDisabledCount() { return mListeningDisabledCount.get(); } + + public void setErrorCode(@SatelliteManager.SatelliteResult int errorCode) { + mErrorCode = errorCode; + } } private static class TestSatelliteSessionController extends SatelliteSessionController { TestSatelliteSessionController(Context context, Looper looper, boolean isSatelliteSupported, - SatelliteModemInterface satelliteModemInterface, - long satelliteStayAtListeningFromSendingMillis, - long satelliteStayAtListeningFromReceivingMillis) { - super(context, looper, isSatelliteSupported, satelliteModemInterface, - satelliteStayAtListeningFromSendingMillis, - satelliteStayAtListeningFromReceivingMillis); + SatelliteModemInterface satelliteModemInterface) { + super(context, looper, isSatelliteSupported, satelliteModemInterface); } - public String getCurrentStateName() { + String getCurrentStateName() { return getCurrentState().getName(); } - public boolean isSendingTriggeredDuringTransferringState() { + boolean isSendingTriggeredDuringTransferringState() { return mIsSendingTriggeredDuringTransferringState.get(); } + + boolean isNbIotInactivityTimerStarted() { + return hasMessages(EVENT_NB_IOT_INACTIVITY_TIMER_TIMED_OUT); + } } private static class TestSatelliteStateCallback extends ISatelliteStateCallback.Stub { diff --git a/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java b/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java new file mode 100644 index 0000000000..327a1cb944 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/security/CellularIdentifierDisclosureTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.security; + +import static android.telephony.CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMEI; +import static android.telephony.CellularIdentifierDisclosure.CELLULAR_IDENTIFIER_IMSI; +import static android.telephony.CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST; +import static android.telephony.CellularIdentifierDisclosure.NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.hardware.radio.network.CellularIdentifier; +import android.hardware.radio.network.NasProtocolMessage; +import android.os.Parcel; + +import com.android.internal.telephony.RILUtils; + +import org.junit.Test; + +public class CellularIdentifierDisclosureTest { + + @Test + public void testEqualsAndHash() { + android.telephony.CellularIdentifierDisclosure disclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + + android.telephony.CellularIdentifierDisclosure anotherDislcosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + assertEquals(disclosure, anotherDislcosure); + assertEquals(disclosure.hashCode(), anotherDislcosure.hashCode()); + } + + @Test + public void testNotEqualsAndHash() { + android.telephony.CellularIdentifierDisclosure imsiDisclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + + android.telephony.CellularIdentifierDisclosure imeiDisclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMEI, + "001001", + false); + + assertNotEquals(imsiDisclosure, imeiDisclosure); + assertNotEquals(imsiDisclosure.hashCode(), imeiDisclosure.hashCode()); + } + + @Test + public void testGetters() { + android.telephony.CellularIdentifierDisclosure disclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + + assertEquals(NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, disclosure.getNasProtocolMessage()); + assertEquals(CELLULAR_IDENTIFIER_IMSI, disclosure.getCellularIdentifier()); + assertEquals(false, disclosure.isEmergency()); + assertEquals("001001", disclosure.getPlmn()); + } + + @Test + public void testParcel() { + android.telephony.CellularIdentifierDisclosure disclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, + CELLULAR_IDENTIFIER_IMSI, + "001001", + false); + + Parcel p = Parcel.obtain(); + disclosure.writeToParcel(p, 0); + p.setDataPosition(0); + + android.telephony.CellularIdentifierDisclosure fromParcel = + android.telephony.CellularIdentifierDisclosure.CREATOR.createFromParcel(p); + assertEquals(disclosure, fromParcel); + } + + @Test + public void testConvertCellularIdentifierDisclosure() { + android.hardware.radio.network.CellularIdentifierDisclosure aidlDisclsoure = + new android.hardware.radio.network.CellularIdentifierDisclosure(); + aidlDisclsoure.plmn = "001001"; + aidlDisclsoure.identifier = NasProtocolMessage.IDENTITY_RESPONSE; + aidlDisclsoure.protocolMessage = CellularIdentifier.IMEI; + aidlDisclsoure.isEmergency = true; + + android.telephony.CellularIdentifierDisclosure expectedDisclosure = + new android.telephony.CellularIdentifierDisclosure( + NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE, + CELLULAR_IDENTIFIER_IMEI, + "001001", + true); + + assertEquals( + expectedDisclosure, RILUtils.convertCellularIdentifierDisclosure(aidlDisclsoure)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java index 0358809584..b42e6d6288 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -26,8 +26,10 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; @@ -49,6 +51,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.flags.FeatureFlags; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import org.junit.After; @@ -117,10 +120,16 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { static final int FAKE_TP_MESSAGE_REFERENCE2 = 456; static final int FAKE_USER_ID1 = 10; static final int FAKE_USER_ID2 = 11; + static final int FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED = 1; + static final int FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED = 0; + static final int FAKE_SATELLITE_IS_NTN_ENABLED = 1; + static final int FAKE_SATELLITE_IS_NTN_DISABLED = 0; static final String FAKE_MAC_ADDRESS1 = "DC:E5:5B:38:7D:40"; static final String FAKE_MAC_ADDRESS2 = "DC:B5:4F:47:F3:4C"; + private FeatureFlags mFeatureFlags; + static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = new SubscriptionInfoInternal.Builder() .setId(1) @@ -186,6 +195,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE1) .setUserId(FAKE_USER_ID1) .setSatelliteEnabled(0) + .setSatelliteAttachEnabledForCarrier( + FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED) + .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_DISABLED) .setGroupDisabled(false) .build(); @@ -254,6 +266,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2) .setUserId(FAKE_USER_ID2) .setSatelliteEnabled(1) + .setSatelliteAttachEnabledForCarrier( + FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED) + .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED) .setGroupDisabled(false) .build(); @@ -406,14 +421,16 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { ((Runnable) invocation.getArguments()[0]).run(); return null; }).when(mSubscriptionDatabaseManagerCallback).invokeFromExecutor(any(Runnable.class)); + mFeatureFlags = Mockito.mock(FeatureFlags.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); doReturn(1).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID1)); doReturn(2).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID2)); + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true); mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), - mSubscriptionDatabaseManagerCallback); + mFeatureFlags, mSubscriptionDatabaseManagerCallback); logd("SubscriptionDatabaseManagerTest -Setup!"); } @@ -518,7 +535,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, false); mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), - mSubscriptionDatabaseManagerCallback); + mFeatureFlags, mSubscriptionDatabaseManagerCallback); assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) .isEqualTo(1); @@ -1930,6 +1947,115 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { } @Test + public void testUpdateCarrierHandoverToSatelliteEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setSatelliteAttachEnabledForCarrier( + FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED) + .build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER)) + .isEqualTo(FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED); + + mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_SATELLITE_ATTACH_ENABLED_FOR_CARRIER, + FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()) + .getSatelliteAttachEnabledForCarrier()) + .isEqualTo(FAKE_SATELLITE_ATTACH_FOR_CARRIER_DISABLED); + } + + @Test + public void testUpdateSatelliteNtn() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNtn(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_IS_NTN_ENABLED)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNtn(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_IS_NTN_ENABLED); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED) + .build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_IS_NTN)).isEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED); + + mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_IS_NTN, FAKE_SATELLITE_IS_NTN_DISABLED); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getOnlyNonTerrestrialNetwork()) + .isEqualTo(FAKE_SATELLITE_IS_NTN_DISABLED); + } + + @Test + public void testUpdateSatelliteNtnWithFeatureDisabled() throws Exception { + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setSatelliteAttachEnabledForCarrier( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + FAKE_SATELLITE_IS_NTN_DISABLED); + processAllMessages(); + + when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false); + reset(mSubscriptionDatabaseManagerCallback); + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setOnlyNonTerrestrialNetwork(FAKE_SATELLITE_IS_NTN_ENABLED) + .build(); + + int subId = subInfo.getSubscriptionId(); + // Verify the cache value is not same as the inserted one. + assertWithMessage("Subscription info cache value is not different.") + .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isNotEqualTo(subInfo); + + // Load subscription info from the database. + mDatabaseManagerUT.reloadDatabaseSync(); + processAllMessages(); + + // Verify the database value is not same as the inserted one. + assertWithMessage("Subscription info database value is not different.") + .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isNotEqualTo(subInfo); + + verify(mSubscriptionDatabaseManagerCallback, never()).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_IS_NTN)).isNotEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED); + + mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_IS_NTN, FAKE_SATELLITE_IS_NTN_ENABLED); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getOnlyNonTerrestrialNetwork()) + .isNotEqualTo(FAKE_SATELLITE_IS_NTN_ENABLED); + } + + @Test public void testUpdateSubscriptionsInGroup() throws Exception { insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO2); @@ -2033,7 +2159,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { } }; assertThat(callback.getExecutor()).isEqualTo(executor); - mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), callback); + mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), + mFeatureFlags, callback); processAllMessages(); assertThat(latch.getCount()).isEqualTo(1); diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java index e03256bb7a..2505f325bb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java @@ -101,7 +101,13 @@ public class SubscriptionInfoInternalTest { .FAKE_TP_MESSAGE_REFERENCE1) .setUserId(SubscriptionDatabaseManagerTest.FAKE_USER_ID1) .setSatelliteEnabled(1) + .setSatelliteAttachEnabledForCarrier( + SubscriptionDatabaseManagerTest + .FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED) + .setOnlyNonTerrestrialNetwork( + SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_ENABLED) .setGroupDisabled(false) + .setOnlyNonTerrestrialNetwork(1) .build(); private final SubscriptionInfoInternal mSubInfoNull = @@ -211,7 +217,13 @@ public class SubscriptionInfoInternalTest { SubscriptionDatabaseManagerTest.FAKE_TP_MESSAGE_REFERENCE1); assertThat(mSubInfo.getUserId()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_USER_ID1); assertThat(mSubInfo.getSatelliteEnabled()).isEqualTo(1); + assertThat(mSubInfo.getSatelliteAttachEnabledForCarrier()) + .isEqualTo(SubscriptionDatabaseManagerTest + .FAKE_SATELLITE_ATTACH_FOR_CARRIER_ENABLED); + assertThat(mSubInfo.getOnlyNonTerrestrialNetwork()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_SATELLITE_IS_NTN_ENABLED); assertThat(mSubInfo.isGroupDisabled()).isFalse(); + assertThat(mSubInfo.getOnlyNonTerrestrialNetwork()).isEqualTo(1); } @Test @@ -274,6 +286,7 @@ public class SubscriptionInfoInternalTest { assertThat(subInfo.getPortIndex()).isEqualTo( SubscriptionManager.USAGE_SETTING_DEFAULT); assertThat(subInfo.isGroupDisabled()).isFalse(); + assertThat(subInfo.isOnlyNonTerrestrialNetwork()).isTrue(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java index aea79656c1..eecaf903c4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -104,7 +104,10 @@ import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.euicc.EuiccController; +import com.android.internal.telephony.flags.FeatureFlags; +import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; +import com.android.internal.telephony.subscription.SubscriptionManagerService.BinderWrapper; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap; import com.android.internal.telephony.uicc.IccCardStatus; @@ -153,7 +156,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; - + private FeatureFlags mFlags; + private BinderWrapper mBinder; private Set<Integer> mActiveSubs = new ArraySet<>(); @Rule @@ -194,12 +198,18 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2)); + mBinder = Mockito.mock(BinderWrapper.class); + doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle(); + replaceInstance(SubscriptionManagerService.class, "BINDER_WRAPPER", null, mBinder); + doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); - mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); + mFlags = Mockito.mock(FeatureFlags.class); + mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper(), + mFlags); monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper())); @@ -253,6 +263,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); } + private SubscriptionDatabaseManagerCallback getSubscriptionDatabaseCallback() throws Exception { + Field field = SubscriptionDatabaseManager.class.getDeclaredField("mCallback"); + field.setAccessible(true); + return (SubscriptionDatabaseManagerCallback) field.get(getSubscriptionDatabaseManager()); + } + /** * Insert the subscription info to the database. This is an instant insertion method. For real * insertion sequence please use {@link #testInsertNewSim()}. @@ -262,7 +278,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { */ private int insertSubscription(@NonNull SubscriptionInfoInternal subInfo) { try { - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo); @@ -274,17 +289,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { field.setAccessible(true); SubscriptionMap<Integer, Integer> map = (SubscriptionMap<Integer, Integer>) field.get(mSubscriptionManagerServiceUT); - Class[] cArgs = new Class[2]; - cArgs[0] = Object.class; - cArgs[1] = Object.class; if (subInfo.getSimSlotIndex() >= 0) { // Change the slot -> subId mapping map.put(subInfo.getSimSlotIndex(), subId); } - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); - processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); @@ -756,13 +766,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Should get an empty list without READ_PHONE_STATE. assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( - CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty(); // Grant READ_PHONE_STATE permission for insertion. mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); List<SubscriptionInfo> subInfos = mSubscriptionManagerServiceUT - .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true); assertThat(subInfos).hasSize(1); assertThat(subInfos.get(0).getIccId()).isEmpty(); assertThat(subInfos.get(0).getCardString()).isEmpty(); @@ -773,7 +783,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { setCarrierPrivilegesForSubId(true, 1); subInfos = mSubscriptionManagerServiceUT - .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true); assertThat(subInfos).hasSize(1); assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } @@ -953,15 +963,15 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Should fail without READ_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT - .getActiveSubInfoCount(CALLING_PACKAGE, CALLING_FEATURE)); + .getActiveSubInfoCount(CALLING_PACKAGE, CALLING_FEATURE, true)); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount( - CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(2); + CALLING_PACKAGE, CALLING_FEATURE, true)).isEqualTo(2); } @Test - public void testSetIconTint() throws Exception { + public void testSetIconTint() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without MODIFY_PHONE_STATE @@ -1110,8 +1120,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testIsSubscriptionAssociatedWithUser() { - insertSubscription(FAKE_SUBSCRIPTION_INFO1); - // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .isSubscriptionAssociatedWithUser(1, FAKE_USER_HANDLE)); @@ -1122,6 +1130,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + // Should fail for non-existent sub Id + assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT + .isSubscriptionAssociatedWithUser(1, FAKE_USER_HANDLE)); + + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle(FAKE_USER_HANDLE, 1); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); @@ -1143,6 +1157,300 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test + @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, + SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER}) + public void testIsSubscriptionAssociatedWithUserMultiSubs() { + doReturn(true).when(mFlags).workProfileApiSplit(); + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_NULL), 1); + + // Verify sub 1 unassociated is visible to all profiles + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true); + + // Assign sub 2 to work profile + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + FAKE_MANAGED_PROFILE_USER_HANDLE, 2); + processAllMessages(); + // Verify work profile can only see its dedicated sub 2 + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false); + // Verify personal profile can only see the unassigned sub 1 + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2, + FAKE_USER_HANDLE)).isEqualTo(false); + + // Sub 2 is deactivated, but still on device, verify visibility doesn't change. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_NOT_READY, null, null); + processAllMessages(); + // Verify work profile can only see its dedicated sub 2 + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false); + // Verify personal profile can only see the unassigned sub 1 + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(2, + FAKE_USER_HANDLE)).isEqualTo(false); + + // Sub 2 is removed from the device. + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_ABSENT, null, null); + processAllMessages(); + // Verify the visibility of the unassigned sub 1 is restored to both profiles. + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_USER_HANDLE)).isEqualTo(true); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(true); + } + + @Test + @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, + SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER}) + public void testSubscriptionAssociationWorkProfileCallerVisibility() { + // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to + // the unassociated sub. + doReturn(true).when(mFlags).workProfileApiSplit(); + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + // Sub 1 is associated with work profile; Sub 2 is unassociated. + int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + FAKE_MANAGED_PROFILE_USER_HANDLE, subId1); + int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_NULL), subId2); + // Set Sub 1 default data sub + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1); + processAllMessages(); + + // Calling from work profile + doReturn(FAKE_MANAGED_PROFILE_USER_HANDLE).when(mBinder).getCallingUserHandle(); + + // Test getAccessibleSubscriptionInfoList + doReturn(true).when(mEuiccManager).isEnabled(); + doReturn(true).when(mSubscriptionManager).canManageSubscription( + any(SubscriptionInfo.class), eq(CALLING_PACKAGE)); + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); + // Test getActiveSubIdList, System + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/)) + .isEqualTo(new int[]{subId1, subId2}); + // Test get getActiveSubInfoCount + assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount( + CALLING_PACKAGE, CALLING_FEATURE, false)).isEqualTo(1); + // Test getActiveSubscriptionInfo + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo( + subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo( + subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2); + // Test getActiveSubscriptionInfoForIccId + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( + FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( + FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId2); + // Test getActiveSubscriptionInfoForSimSlotIndex + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId2); + // Test getActiveSubscriptionInfoList + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE, false) + .stream().map(SubscriptionInfo::getSubscriptionId) + .toList()).isEqualTo(List.of(subId1)); + // Test getAllSubInfoList + assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1)); + // Test getAvailableSubscriptionInfoList + assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1, subId2)); + // Test getDefaultDataSubId + assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1); + // Test getDefault<Sms/Voice>SubIdAsUser + assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser( + FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser( + FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser( + FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + // Test getEnabledSubscriptionId + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo( + subId1); + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( + subId2); + // Test getOpportunisticSubscriptions + mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE); + mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE); + processAllMessages(); + assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1, subId2)); + // Test getSubscriptionInfo - can get both as it's an internal getter + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId()) + .isEqualTo(subId2); + // Test getSubscriptionInfoListAssociatedWithUser + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser( + FAKE_MANAGED_PROFILE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId) + .toList()).isEqualTo(List.of(subId1)); + // Test getSubscriptionsInGroup + setCarrierPrivilegesForSubId(true, subId1); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE) + .stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1)); + // Test isActiveSubId + assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE, + CALLING_FEATURE)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE, + CALLING_FEATURE)).isTrue(); + // Test isSubscriptionEnabled + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue(); + } + + @Test + @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, + SubscriptionManagerService.FILTER_ACCESSIBLE_SUBS_BY_USER}) + public void testSubscriptionAssociationPersonalCallerVisibility() { + // Split mode is defined as when a profile owns a dedicated sub, it loses the visibility to + // the unassociated sub. + doReturn(true).when(mFlags).workProfileApiSplit(); + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + // Sub 1 is unassociated; Sub 2 is associated with work profile. + int subId1 = insertSubscription(FAKE_SUBSCRIPTION_INFO1); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_NULL), subId1); + int subId2 = insertSubscription(FAKE_SUBSCRIPTION_INFO2); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle( + FAKE_MANAGED_PROFILE_USER_HANDLE, subId2); + // Set Sub 1 default data sub + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.setDefaultDataSubId(subId1); + processAllMessages(); + + // Calling from a profile that owns no dedicated subs. + doReturn(FAKE_USER_HANDLE).when(mBinder).getCallingUserHandle(); + + // Test getAccessibleSubscriptionInfoList + doReturn(true).when(mEuiccManager).isEnabled(); + doReturn(true).when(mSubscriptionManager).canManageSubscription( + any(SubscriptionInfo.class), eq(CALLING_PACKAGE)); + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); + // Test getActiveSubIdList, System + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false/*visible only*/)) + .isEqualTo(new int[]{subId1, subId2}); + // Test get getActiveSubInfoCount + assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount( + CALLING_PACKAGE, CALLING_FEATURE, false)).isEqualTo(1); + // Test getActiveSubscriptionInfo + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo( + subId1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfo( + subId2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()).isEqualTo(subId2); + // Test getActiveSubscriptionInfoForIccId + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( + FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( + FAKE_ICCID2, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId2); + // Test getActiveSubscriptionInfoForSimSlotIndex + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 0, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 1, CALLING_PACKAGE, CALLING_FEATURE).getSubscriptionId()) + .isEqualTo(subId2); + // Test getActiveSubscriptionInfoList + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE, false).stream() + .map(SubscriptionInfo::getSubscriptionId) + .toList()).isEqualTo(List.of(subId1)); + // Test getAllSubInfoList + assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1)); + // Test getAvailableSubscriptionInfoList + assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1, subId2)); + // Test getDefaultDataSubId + assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(subId1); + // Test getDefault<Sms/Voice>SubIdAsUser + assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubIdAsUser( + FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getDefaultSubIdAsUser( + FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubIdAsUser( + FAKE_USER_HANDLE.getIdentifier())).isEqualTo(subId1); + // Test getEnabledSubscriptionId + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo( + subId1); + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( + subId2); + // Test getOpportunisticSubscriptions + mSubscriptionManagerServiceUT.setOpportunistic(true, subId1, CALLING_PACKAGE); + mSubscriptionManagerServiceUT.setOpportunistic(true, subId2, CALLING_PACKAGE); + processAllMessages(); + assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions(CALLING_PACKAGE, + CALLING_FEATURE).stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1, subId2)); + // Test getSubscriptionInfo - can get both as it's an internal getter + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId1).getSubscriptionId()) + .isEqualTo(subId1); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(subId2).getSubscriptionId()) + .isEqualTo(subId2); + // Test getSubscriptionInfoListAssociatedWithUser + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoListAssociatedWithUser( + FAKE_USER_HANDLE).stream().map(SubscriptionInfo::getSubscriptionId) + .toList()).isEqualTo(List.of(subId1)); + // Test getSubscriptionsInGroup + setCarrierPrivilegesForSubId(true, subId1); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE) + .stream().map(SubscriptionInfo::getSubscriptionId).toList()) + .isEqualTo(List.of(subId1)); + // Test isActiveSubId + assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId1, CALLING_PACKAGE, + CALLING_FEATURE)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isActiveSubId(subId2, CALLING_PACKAGE, + CALLING_FEATURE)).isTrue(); + // Test isSubscriptionEnabled + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId1)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(subId2)).isTrue(); + } + + @Test public void testSetUsageSetting() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); @@ -1844,7 +2152,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( CALLING_PACKAGE, CALLING_FEATURE).isEmpty()).isTrue(); assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( - CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty(); } @Test @@ -2050,7 +2358,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { verify(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT - .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true); assertThat(subInfoList).hasSize(1); assertThat(subInfoList.get(0).getSimSlotIndex()).isEqualTo(1); assertThat(subInfoList.get(0).getSubscriptionId()).isEqualTo(1); @@ -2168,7 +2476,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { processAllMessages(); List<SubscriptionInfo> subInfoList = mSubscriptionManagerServiceUT - .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE, true); assertThat(subInfoList).hasSize(1); assertThat(subInfoList.get(0).isActive()).isTrue(); @@ -2288,16 +2596,17 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( - CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + CALLING_PACKAGE, CALLING_FEATURE, true)).isEmpty(); setIdentifierAccess(true); mSubscriptionManagerServiceUT.addSubInfo(FAKE_MAC_ADDRESS2, FAKE_CARRIER_NAME2, 0, SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isNotEmpty(); assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( - CALLING_PACKAGE, CALLING_FEATURE)).isNotEmpty(); + CALLING_PACKAGE, CALLING_FEATURE, true)).isNotEmpty(); assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( - CALLING_PACKAGE, CALLING_FEATURE).get(0).getIccId()).isEqualTo(FAKE_MAC_ADDRESS2); + CALLING_PACKAGE, CALLING_FEATURE, true).get(0).getIccId()) + .isEqualTo(FAKE_MAC_ADDRESS2); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java index 2ab23f3f19..9265a62ccb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java @@ -495,40 +495,6 @@ public class UiccControllerTest extends TelephonyTest { assertEquals(uiccCardInfo, mUiccControllerUT.getAllUiccCardInfos().get(0)); } - @Test - public void testEidNotSupported() { - // Give UiccController a real context so it can use shared preferences - mUiccControllerUT.mContext = InstrumentationRegistry.getContext(); - - // Mock out UiccSlots - mUiccControllerUT.mUiccSlots[0] = mMockSlot; - doReturn(true).when(mMockSlot).isEuicc(); - doReturn(mMockEuiccCard).when(mMockSlot).getUiccCard(); - doReturn(null).when(mMockEuiccCard).getEid(); - - // simulate card status loaded so that the UiccController sets the card ID - IccCardStatus ics = new IccCardStatus(); - ics.setCardState(1 /* present */); - ics.setUniversalPinState(3 /* disabled */); - ics.atr = "abcdef0123456789abcdef"; - ics.iccid = "123451234567890"; - ics.mSlotPortMapping = new IccSlotPortMapping(); - ics.mSlotPortMapping.mPhysicalSlotIndex = UiccController.INVALID_SLOT_ID; - // make it seem like EID is not supported by setting physical slot = -1 like on HAL < 1.2 - - mSimulatedCommands.setSupportsEid(false); - - AsyncResult ar = new AsyncResult(null, ics, null); - Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar); - mUiccControllerUT.handleMessage(msg); - - // assert that the default eUICC card Id is UNSUPPORTED_CARD_ID - assertEquals(TelephonyManager.UNSUPPORTED_CARD_ID, - mUiccControllerUT.getCardIdForDefaultEuicc()); - - mSimulatedCommands.setSupportsEid(true); - } - /** * The default eUICC should not be the removable slot if there is a built-in eUICC. */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 230f147e32..1d320a34b4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -42,7 +42,6 @@ import org.junit.Before; import org.junit.Test; public class UiccSlotTest extends TelephonyTest { - private UiccSlot mUiccSlot; private UiccSlotTestHandlerThread mTestHandlerThread; private Handler mTestHandler; @@ -263,7 +262,7 @@ public class UiccSlotTest extends TelephonyTest { // assert on updated values assertTrue(mUiccSlot.isActive()); - assertEquals(mUiccSlot.getMinimumVoltageClass(), UiccSlot.VOLTAGE_CLASS_A); + assertEquals(UiccSlot.VOLTAGE_CLASS_A, mUiccSlot.getMinimumVoltageClass()); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java index 7e51badd40..d5b6ccb80c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java @@ -50,7 +50,6 @@ public class UiccStateChangedLauncherTest extends TelephonyTest { private static final String PROVISIONING_PACKAGE_NAME = "test.provisioning.package"; // Mocked classes - private Context mContext; private Resources mResources; private IccCardStatus makeCardStatus(CardState state) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java index b6dd7bd2d0..c38be60575 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java @@ -52,7 +52,6 @@ public class EuiccCardTest extends TelephonyTest { private static class ResultCaptor<T> extends AsyncResultCallback<T> { public T result; - public Throwable exception; private CountDownLatch mLatch; @@ -68,7 +67,6 @@ public class EuiccCardTest extends TelephonyTest { @Override public void onException(Throwable e) { - exception = e; mLatch.countDown(); } } |