Merge "Put additional logs to check ResultReceiver created over limit" into main
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 226ab18..f553698 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -284,33 +284,33 @@
     <string name="data_enable_summary" msgid="696860063456536557">"Dozvoli korištenje podataka"</string>
     <string name="dialog_alert_title" msgid="5260471806940268478">"Pažnja"</string>
     <string name="roaming" msgid="1576180772877858949">"Roming"</string>
-    <string name="roaming_enable" msgid="6853685214521494819">"Povezivanje na usluge prijenosa podataka u romingu"</string>
-    <string name="roaming_disable" msgid="8856224638624592681">"Povezivanje na usluge prijenosa podataka u romingu"</string>
+    <string name="roaming_enable" msgid="6853685214521494819">"Povezivanje na usluge prenosa podataka u romingu"</string>
+    <string name="roaming_disable" msgid="8856224638624592681">"Povezivanje na usluge prenosa podataka u romingu"</string>
     <string name="roaming_reenable_message" msgid="1951802463885727915">"Roming podataka je isključen. Dodirnite da ga uključite."</string>
     <string name="roaming_enabled_message" msgid="9022249120750897">"Mogu nastati troškovi za roming. Dodirnite da izmijenite."</string>
-    <string name="roaming_notification_title" msgid="3590348480688047320">"Veza za prijenos podataka na mobilnoj mreži je izgubljena"</string>
+    <string name="roaming_notification_title" msgid="3590348480688047320">"Veza za prenos podataka na mobilnoj mreži je izgubljena"</string>
     <string name="roaming_on_notification_title" msgid="7451473196411559173">"Roming podataka je uključen"</string>
     <string name="roaming_warning" msgid="7855681468067171971">"Može dovesti do značajnih troškova."</string>
     <string name="roaming_check_price_warning" msgid="8212484083990570215">"Raspitajte se kod svog mobilnog operatera za cijene."</string>
     <string name="roaming_alert_title" msgid="5689615818220960940">"Dozvoliti roming podataka?"</string>
     <string name="limited_sim_function_notification_title" msgid="612715399099846281">"Ograničena funkcionalnost SIM-a"</string>
-    <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"Pozivi i usluge prijenosa podataka operatera <xliff:g id="CARRIER_NAME">%1$s</xliff:g> mogu biti blokirane kada koristite broj <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>."</string>
-    <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"Pozivi i usluge prijenosa pod. op. <xliff:g id="CARRIER_NAME">%1$s</xliff:g> mogu biti blok. kada koristite drugi SIM."</string>
+    <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"Pozivi i usluge prenosa podataka operatera <xliff:g id="CARRIER_NAME">%1$s</xliff:g> mogu biti blokirane kada koristite broj <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>."</string>
+    <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"Pozivi i usluge prenosa pod. op. <xliff:g id="CARRIER_NAME">%1$s</xliff:g> mogu biti blok. kada koristite drugi SIM."</string>
     <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"Zastarjeli SIP računi su pronađeni i uklonjeni"</string>
     <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Android platforma više ne podržva SIP pozivanje.\nVaši postojeći SIP računi <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> su uklonjeni.\nPotvrdite zadanu postavku računa za pozivanje."</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"Idi u postavke"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"Prijenos podataka u aplikaciji"</string>
-    <string name="data_usage_template" msgid="6287906680674061783">"Iskorišteno je <xliff:g id="ID_1">%1$s</xliff:g> prijenosa podataka u periodu <xliff:g id="ID_2">%2$s</xliff:g>"</string>
+    <string name="data_usage_template" msgid="6287906680674061783">"Iskorišteno je <xliff:g id="ID_1">%1$s</xliff:g> prenosa podataka u periodu <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="advanced_options_title" msgid="9208195294513520934">"Napredno"</string>
     <string name="carrier_settings_euicc" msgid="1190237227261337749">"Operater"</string>
     <string name="keywords_carrier_settings_euicc" msgid="8540160967922063745">"mobilni operater, esim, sim, euicc, promijeni mobilnog operatera, dodaj mobilnog operatera"</string>
     <string name="carrier_settings_euicc_summary" msgid="2027941166597330117">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> — <xliff:g id="PHONE_NUMBER">%2$s</xliff:g>"</string>
     <string name="mobile_data_settings_title" msgid="7228249980933944101">"Prijenos podataka na mobilnoj mreži"</string>
-    <string name="mobile_data_settings_summary" msgid="5012570152029118471">"Pristup prijenosu podataka mobilnom mrežom"</string>
+    <string name="mobile_data_settings_summary" msgid="5012570152029118471">"Pristup prenosu podataka mobilnom mrežom"</string>
     <string name="data_usage_disable_mobile" msgid="5669109209055988308">"Isključiti prijenos podataka na mobilnoj mreži?"</string>
     <string name="sim_selection_required_pref" msgid="6985901872978341314">"Potreban izbor"</string>
-    <string name="sim_change_data_title" msgid="9142726786345906606">"Promijeniti SIM za prijenos podataka?"</string>
-    <string name="sim_change_data_message" msgid="3567358694255933280">"Koristiti SIM karticu <xliff:g id="NEW_SIM">%1$s</xliff:g> umjesto SIM kartice <xliff:g id="OLD_SIM">%2$s</xliff:g> za prijenos podataka na mobilnoj mreži?"</string>
+    <string name="sim_change_data_title" msgid="9142726786345906606">"Promijeniti SIM za prenos podataka?"</string>
+    <string name="sim_change_data_message" msgid="3567358694255933280">"Koristiti SIM karticu <xliff:g id="NEW_SIM">%1$s</xliff:g> umjesto SIM kartice <xliff:g id="OLD_SIM">%2$s</xliff:g> za prenos podataka na mobilnoj mreži?"</string>
     <string name="wifi_calling_settings_title" msgid="5800018845662016507">"Pozivanje putem WiFi-ja"</string>
     <string name="video_calling_settings_title" msgid="342829454913266078">"Video pozivi putem operatera"</string>
     <string name="gsm_umts_options" msgid="4968446771519376808">"GSM/UMTS opcije"</string>
@@ -318,13 +318,13 @@
     <string name="throttle_data_usage" msgid="1944145350660420711">"Korištenje podataka"</string>
     <string name="throttle_current_usage" msgid="7483859109708658613">"Iskorišteni podaci u trenutnom periodu"</string>
     <string name="throttle_time_frame" msgid="1813452485948918791">"Period korištenja podataka"</string>
-    <string name="throttle_rate" msgid="7641913901133634905">"Pravila o brzini prijenosa podataka"</string>
+    <string name="throttle_rate" msgid="7641913901133634905">"Pravila o brzini prenosa podataka"</string>
     <string name="throttle_help" msgid="2624535757028809735">"Saznajte više"</string>
     <string name="throttle_status_subtext" msgid="1110276415078236687">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g> ٪) od <xliff:g id="USED_2">%3$s</xliff:g> maksimuma perioda\nSljedeći period počinje za <xliff:g id="USED_3">%4$d</xliff:g> dan(a) (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
     <string name="throttle_data_usage_subtext" msgid="3185429653996709840">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g> ٪) od <xliff:g id="USED_2">%3$s</xliff:g> maksimuma perioda"</string>
-    <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"<xliff:g id="USED_0">%1$s</xliff:g> ograničenje je prekoračeno \nBrzina prijenosa podataka je smanjena na <xliff:g id="USED_1">%2$d</xliff:g> Kb/s"</string>
+    <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"<xliff:g id="USED_0">%1$s</xliff:g> ograničenje je prekoračeno \nBrzina prenosa podataka je smanjena na <xliff:g id="USED_1">%2$d</xliff:g> Kb/s"</string>
     <string name="throttle_time_frame_subtext" msgid="6462089615392402127">"Proteklo je <xliff:g id="USED_0">%1$d</xliff:g> ٪ ciklusa\nSljedeći period počinje za <xliff:g id="USED_1">%2$d</xliff:g> dan(a) (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
-    <string name="throttle_rate_subtext" msgid="7221971817325779535">"Brzina prijenosa podataka se smanjuje na <xliff:g id="USED">%1$d</xliff:g> Kb/s ako se prekorači ograničenje korištenja podataka"</string>
+    <string name="throttle_rate_subtext" msgid="7221971817325779535">"Brzina prenosa podataka se smanjuje na <xliff:g id="USED">%1$d</xliff:g> Kb/s ako se prekorači ograničenje korištenja podataka"</string>
     <string name="throttle_help_subtext" msgid="2817114897095534807">"Više informacija o pravilima korištenja podataka mobilne mreže vašeg operatera"</string>
     <string name="cell_broadcast_sms" msgid="4053449797289031063">"SMS info servisa"</string>
     <string name="enable_disable_cell_bc_sms" msgid="4759958924031721350">"SMS info servisa"</string>
@@ -553,7 +553,7 @@
     <string name="incall_error_supp_service_switch" msgid="5272822448189448479">"Nije moguće prebacivati pozive."</string>
     <string name="incall_error_supp_service_resume" msgid="1276861499306817035">"Nije moguće nastaviti poziv."</string>
     <string name="incall_error_supp_service_separate" msgid="8932660028965274353">"Nije moguće odvojiti poziv."</string>
-    <string name="incall_error_supp_service_transfer" msgid="8211925891867334323">"Prijenos nije moguć."</string>
+    <string name="incall_error_supp_service_transfer" msgid="8211925891867334323">"Prenos nije moguć."</string>
     <string name="incall_error_supp_service_conference" msgid="27578082433544702">"Nije moguće spajati pozive."</string>
     <string name="incall_error_supp_service_reject" msgid="3044363092441655912">"Nije moguće odbiti poziv."</string>
     <string name="incall_error_supp_service_hangup" msgid="836524952243836735">"Nije moguće uputiti poziv(e)."</string>
@@ -621,7 +621,7 @@
     <string name="ota_title_activate" msgid="4049645324841263423">"Aktivirajte svoj telefon"</string>
     <string name="ota_touch_activate" msgid="838764494319694754">"Za aktiviranje telefonske usluge potrebno je uputiti poseban poziv. \n\nNakon što pritisnete „Aktiviraj“, poslušajte uputstva za aktiviranje telefona."</string>
     <string name="ota_hfa_activation_title" msgid="3300556778212729671">"Aktivacija u toku..."</string>
-    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefon aktivira uslugu prijenosa mobilnih podataka.\n\nTo može potrajati do 5 minuta."</string>
+    <string name="ota_hfa_activation_dialog_message" msgid="7921718445773342996">"Telefon aktivira uslugu prenosa mobilnih podataka.\n\nTo može potrajati do 5 minuta."</string>
     <string name="ota_skip_activation_dialog_title" msgid="7666611236789203797">"Preskočiti aktivaciju?"</string>
     <string name="ota_skip_activation_dialog_message" msgid="6691722887019708713">"Ako preskočite aktivaciju, nećete moći upućivati pozive niti se povezati na mobilne podatkovne mreže (iako se možete povezati s WiFi mrežama). Dok ne aktivirate telefon, prikazivat će se upit za aktivaciju svaki put kada upalite telefon."</string>
     <string name="ota_skip_activation_dialog_skip_label" msgid="5908029466817825633">"Preskoči"</string>
@@ -642,7 +642,7 @@
     <string name="phone_entered_ecm_text" msgid="8431238297843035842">"Aktiviran način rada za hitni povratni poziv"</string>
     <string name="phone_in_ecm_notification_title" msgid="6825016389926367946">"Način rada za hitni povratni poziv"</string>
     <string name="phone_in_ecm_call_notification_text" msgid="653972232922670335">"Podatkovna veza je onemogućena"</string>
-    <string name="phone_in_ecm_notification_complete_time" msgid="7341624337163082759">"Nema veze za prijenos podataka do <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
+    <string name="phone_in_ecm_notification_complete_time" msgid="7341624337163082759">"Nema veze za prenos podataka do <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <!-- format error in translation for alert_dialog_exit_ecm (7661603870224398025) -->
     <!-- format error in translation for alert_dialog_not_avaialble_in_ecm (8717711120099503279) -->
     <string name="alert_dialog_in_ecm_call" msgid="1207545603149771978">"Odabrana radnja nije dostupna tokom hitnog poziva."</string>
@@ -707,10 +707,10 @@
     <string name="mobile_data_status_roaming_with_plan_subtext" msgid="2576177169108123095">"Trenutno u romingu, plan za podatke je aktivan"</string>
     <string name="mobile_data_status_no_plan_subtext" msgid="170331026419263657">"Nema preostalih mobilnih podataka"</string>
     <string name="mobile_data_activate_prepaid" msgid="4276738964416795596">"Nema preostalih mobilnih podataka"</string>
-    <string name="mobile_data_activate_prepaid_summary" msgid="6846085278531605925">"Dodajte podatke za prijenos na mobilnoj mreži putem operatera <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+    <string name="mobile_data_activate_prepaid_summary" msgid="6846085278531605925">"Dodajte podatke za prenos na mobilnoj mreži putem operatera <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_roaming_plan" msgid="922290995866269366">"Nema plana za roming"</string>
     <string name="mobile_data_activate_roaming_plan_summary" msgid="5379228493306235969">"Dodajte plan za roming pomoću pružaoca usluga <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
-    <string name="mobile_data_activate_footer" msgid="7895874069807204548">"Možete dodati podatke za prijenos na mobilnoj mreži ili plan za roming pomoću operatera, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
+    <string name="mobile_data_activate_footer" msgid="7895874069807204548">"Možete dodati podatke za prenos na mobilnoj mreži ili plan za roming pomoću operatera, <xliff:g id="PROVIDER_NAME">%s</xliff:g>."</string>
     <string name="mobile_data_activate_diag_title" msgid="5401741936224757312">"Dodati podatke?"</string>
     <string name="mobile_data_activate_diag_message" msgid="3527260988020415441">"Možda ćete morati dodati podatke preko pružaoca usluga <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
     <string name="mobile_data_activate_button" msgid="1139792516354374612">"DODAJTE PODATKE"</string>
@@ -830,8 +830,8 @@
     <string name="supp_service_over_ut_precautions_dual_sim" msgid="5166866975550910474">"Za korištenje usluge <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, provjerite je li za SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g> uključen prijenos podataka na mobilnoj mreži. Ovo možete promijeniti u postavkama mobilne mreže."</string>
     <string name="supp_service_over_ut_precautions_roaming_dual_sim" msgid="6627654855191817965">"Za korištenje usluge <xliff:g id="SUPP_SERVICE">%1$s</xliff:g>, provjerite jesu li za SIM <xliff:g id="SIM_NUMBER">%2$d</xliff:g> uključeni prijenos podataka na mobilnoj mreži i roming podataka. Ovo možete promijeniti u postavkama mobilne mreže."</string>
     <string name="supp_service_over_ut_precautions_dialog_dismiss" msgid="5934541487903081652">"Odbaci"</string>
-    <string name="radio_info_data_connection_enable" msgid="6183729739783252840">"Omogućite vezu za prijenos podataka"</string>
-    <string name="radio_info_data_connection_disable" msgid="6404751291511368706">"Onemogući vezu za prijenos podataka"</string>
+    <string name="radio_info_data_connection_enable" msgid="6183729739783252840">"Omogućite vezu za prenos podataka"</string>
+    <string name="radio_info_data_connection_disable" msgid="6404751291511368706">"Onemogući vezu za prenos podataka"</string>
     <string name="volte_provisioned_switch_string" msgid="4812874990480336178">"VoLTE omogućen"</string>
     <string name="vt_provisioned_switch_string" msgid="8295542122512195979">"Video pozivi su omogućeni"</string>
     <string name="wfc_provisioned_switch_string" msgid="3835004640321078988">"WiFi poziv obezbijeđen"</string>
@@ -882,7 +882,7 @@
     <string name="radioInfo_lac" msgid="3892986460272607013">"LAC"</string>
     <string name="radioInfo_cid" msgid="1423185536264406705">"CID"</string>
     <string name="radio_info_subid" msgid="6839966868621703203">"Trenutni pomoćni ID:"</string>
-    <string name="radio_info_dds" msgid="1122593144425697126">"Pomoćni ID za zadani SIM za prijenos podataka:"</string>
+    <string name="radio_info_dds" msgid="1122593144425697126">"Pomoćni ID za zadani SIM za prenos podataka:"</string>
     <string name="radio_info_dl_kbps" msgid="2382922659525318726">"DL propusnost (kbps):"</string>
     <string name="radio_info_ul_kbps" msgid="2102225400904799036">"UL propusnost (kbps):"</string>
     <string name="radio_info_phy_chan_config" msgid="608045501232211303">"Konfiguracije fizičkih kanala:"</string>
@@ -902,7 +902,7 @@
     <string name="radio_info_message_waiting_label" msgid="1886549432566952078">"Poruka na čekanju:"</string>
     <string name="radio_info_phone_number_label" msgid="2533852539562512203">"Broj telefona:"</string>
     <string name="radio_info_voice_network_type_label" msgid="2395347336419593265">"Vrsta glasovne mreže:"</string>
-    <string name="radio_info_data_network_type_label" msgid="8886597029237501929">"Vrsta mreže za prijenos podataka:"</string>
+    <string name="radio_info_data_network_type_label" msgid="8886597029237501929">"Vrsta mreže za prenos podataka:"</string>
     <string name="radio_info_override_network_type_label" msgid="4176280017221092005">"Zaobilaženje vrste mreže:"</string>
     <string name="radio_info_voice_raw_registration_state_label" msgid="2822988327145825128">"Stanje registracije sirovog glasa:"</string>
     <string name="radio_info_data_raw_registration_state_label" msgid="2895895513822604539">"Stanje registracije sirovih podataka:"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ddbec3a..8cb4d1d 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -184,7 +184,7 @@
     <string name="connect_later" msgid="1950138106010005425">"現在このネットワークに接続できません。しばらくしてからもう一度お試しください。"</string>
     <string name="registration_done" msgid="5337407023566953292">"ネットワークに登録されました。"</string>
     <string name="already_auto" msgid="8607068290733079336">"すでに自動選択が適用されています。"</string>
-    <string name="select_automatically" msgid="779750291257872651">"ネットワークを自動的に選択"</string>
+    <string name="select_automatically" msgid="779750291257872651">"ネットワークを自動的に選択する"</string>
     <string name="manual_mode_disallowed_summary" msgid="3970048592179890197">"%1$s に接続中はご利用いただけません"</string>
     <string name="network_select_title" msgid="4117305053881611988">"ネットワーク"</string>
     <string name="register_automatically" msgid="3907580547590554834">"自動登録..."</string>
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 579a853..bda4b28 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -367,7 +367,7 @@
 
     private String mActionEsos;
     private String mActionEsosDemo;
-
+    private Intent mNonEsosIntent;
     private TelephonyDisplayInfo mDisplayInfo;
 
     private List<PhysicalChannelConfig> mPhysicalChannelConfigs = new ArrayList<>();
@@ -785,37 +785,33 @@
         mEsosDemoButton  = (Button) findViewById(R.id.demo_esos_questionnaire);
         mSatelliteEnableNonEmergencyModeButton = (Button) findViewById(
                 R.id.satellite_enable_non_emergency_mode);
-        CarrierConfigManager cm = getSystemService(CarrierConfigManager.class);
-        PersistableBundle bundle = cm.getConfigForSubId(mSubId,
-                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
-                CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
-        if (!bundle.getBoolean(
-                CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false)
-                || !bundle.getBoolean(
-                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false)) {
-            mSatelliteEnableNonEmergencyModeButton.setVisibility(View.GONE);
-        }
-        if (!Build.isDebuggable()) {
-            if (!TextUtils.isEmpty(mActionEsos)) {
-                mEsosButton.setVisibility(View.GONE);
-            }
-            if (!TextUtils.isEmpty(mActionEsosDemo)) {
-                mEsosDemoButton.setVisibility(View.GONE);
-            }
-            mSatelliteEnableNonEmergencyModeButton.setVisibility(View.GONE);
+
+        if (shouldHideButton(mActionEsos)) {
+            mEsosButton.setVisibility(View.GONE);
         } else {
             mEsosButton.setOnClickListener(v -> startActivityAsUser(
                     new Intent(mActionEsos).addFlags(
                             Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK),
                     UserHandle.CURRENT)
             );
+        }
+        if (shouldHideButton(mActionEsosDemo)) {
+            mEsosDemoButton.setVisibility(View.GONE);
+        } else {
             mEsosDemoButton.setOnClickListener(v -> startActivityAsUser(
                     new Intent(mActionEsosDemo).addFlags(
                             Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK),
                     UserHandle.CURRENT)
             );
-            mSatelliteEnableNonEmergencyModeButton.setOnClickListener(v ->
-                    enableSatelliteNonEmergencyMode());
+        }
+        if (shouldHideNonEmergencyMode()) {
+            mSatelliteEnableNonEmergencyModeButton.setVisibility(View.GONE);
+        } else {
+            mSatelliteEnableNonEmergencyModeButton.setOnClickListener(v -> {
+                if (mNonEsosIntent != null) {
+                    sendBroadcast(mNonEsosIntent);
+                }
+            });
         }
 
         mOemInfoButton = (Button) findViewById(R.id.oem_info);
@@ -839,6 +835,21 @@
         restoreFromBundle(icicle);
     }
 
+    boolean shouldHideButton(String action) {
+        if (!Build.isDebuggable()) {
+            return true;
+        }
+        if (TextUtils.isEmpty(action)) {
+            return true;
+        }
+        PackageManager pm = getPackageManager();
+        Intent intent = new Intent(action);
+        if (pm.resolveActivity(intent, 0) == null) {
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public Intent getParentActivityIntent() {
         Intent parentActivity = super.getParentActivityIntent();
@@ -2141,26 +2152,36 @@
                 }
             };
 
-    /**
-     * Enable modem satellite for non-emergency mode.
-     */
-    private void enableSatelliteNonEmergencyMode() {
+    private boolean shouldHideNonEmergencyMode() {
+        if (!Build.isDebuggable()) {
+            return true;
+        }
+        String action  = SatelliteManager.ACTION_SATELLITE_START_NON_EMERGENCY_SESSION;
+        if (TextUtils.isEmpty(action)) {
+            return true;
+        }
+        if (mNonEsosIntent != null) {
+            mNonEsosIntent = null;
+        }
         CarrierConfigManager cm = getSystemService(CarrierConfigManager.class);
         if (cm == null) {
-            loge("enableSatelliteNonEmergencyMode: sm or cm is null");
-            return;
+            loge("shouldHideNonEmergencyMode: cm is null");
+            return true;
         }
-        if (!cm.getConfigForSubId(mSubId,
-                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL)
-                .getBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL)) {
-            loge("enableSatelliteNonEmergencyMode: KEY_SATELLITE_ATTACH_SUPPORTED_BOOL is false");
-            return;
+        PersistableBundle bundle = cm.getConfigForSubId(mSubId,
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+                CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
+        if (!bundle.getBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false)) {
+            log("shouldHideNonEmergencyMode: esos_supported false");
+            return true;
         }
-        log("enableSatelliteNonEmergencyMode: requestEnabled");
-        sendBroadCastForSatelliteNonEmergencyMode();
-    }
+        if (!bundle.getBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false)) {
+            log("shouldHideNonEmergencyMode: attach_supported false");
+            return true;
+        }
 
-    private void sendBroadCastForSatelliteNonEmergencyMode() {
         String packageName = getStringFromOverlayConfig(
                 com.android.internal.R.string.config_satellite_gateway_service_package);
 
@@ -2168,16 +2189,20 @@
                 .config_satellite_carrier_roaming_non_emergency_session_class);
         if (packageName == null || className == null
                 || packageName.isEmpty() || className.isEmpty()) {
-            Log.d(TAG, "sendBroadCastForSatelliteNonEmergencyMode:"
+            Log.d(TAG, "shouldHideNonEmergencyMode:"
                     + " packageName or className is null or empty.");
-            return;
+            return true;
         }
-        String action  = SatelliteManager.ACTION_SATELLITE_START_NON_EMERGENCY_SESSION;
-
+        PackageManager pm = getPackageManager();
         Intent intent = new Intent(action);
         intent.setComponent(new ComponentName(packageName, className));
-        sendBroadcast(intent);
-        Log.d(TAG, "sendBroadCastForSatelliteNonEmergencyMode" + intent);
+        if (pm.queryBroadcastReceivers(intent, 0).isEmpty()) {
+            Log.d(TAG, "shouldHideNonEmergencyMode: Broadcast receiver not found for intent: "
+                    + intent);
+            return true;
+        }
+        mNonEsosIntent = intent;
+        return false;
     }
 
     private String getStringFromOverlayConfig(int resourceId) {
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index c7d97f5..edbbabd 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -651,8 +651,8 @@
             // Check if IMS video pause is supported.
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL);
         }
 
         /**
@@ -697,8 +697,8 @@
         private boolean isCarrierInstantLetteringSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL);
         }
 
         /**
@@ -709,8 +709,8 @@
         private boolean isCarrierAdhocConferenceCallSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL);
         }
 
 
@@ -722,8 +722,8 @@
         private boolean isCarrierMergeCallSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_SUPPORT_CONFERENCE_CALL_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_CONFERENCE_CALL_BOOL);
         }
 
         /**
@@ -734,6 +734,7 @@
         private boolean isCarrierMergeImsCallSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL);
         }
 
@@ -745,8 +746,8 @@
         private boolean isCarrierEmergencyVideoCallsAllowed() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL);
         }
 
         /**
@@ -757,8 +758,8 @@
         private boolean isCarrierVideoConferencingSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null &&
-                    b.getBoolean(CarrierConfigManager.KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL);
+            if (b == null) return false;
+            return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL);
         }
 
         /**
@@ -771,7 +772,8 @@
         private boolean isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
-            return b != null && b.getBoolean(
+            if (b == null) return false;
+            return b.getBoolean(
                     CarrierConfigManager.KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL);
         }
 
@@ -784,6 +786,7 @@
         private boolean isCarrierManageImsConferenceCallSupported() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL);
         }
 
@@ -796,6 +799,7 @@
         private boolean isCarrierUsingSimCallManager() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return !TextUtils.isEmpty(
                     b.getString(CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING));
         }
@@ -810,6 +814,7 @@
         private boolean isCarrierShowPreciseFailedCause() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return b.getBoolean(CarrierConfigManager.KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL);
         }
 
@@ -822,6 +827,7 @@
         private boolean isCarrierUseCallRecordingTone() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return b.getBoolean(CarrierConfigManager.KEY_PLAY_CALL_RECORDING_TONE_BOOL);
         }
 
@@ -831,6 +837,7 @@
         private boolean isCarrierAllowRttWhenRoaming() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return false;
             return b.getBoolean(CarrierConfigManager.KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL);
         }
 
@@ -843,6 +850,7 @@
         private Bundle getPhoneAccountExtras() {
             PersistableBundle b =
                     PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+            if (b == null) return new Bundle();
 
             int instantLetteringMaxLength = b.getInt(
                     CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT);
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 5ecf111..c2f2bfb 100644
--- a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
+++ b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
@@ -47,9 +47,10 @@
 import android.preference.PreferenceManager;
 import android.telephony.RadioAccessFamily;
 import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 
 import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.TelephonyTestBase;
@@ -78,7 +79,8 @@
 /**
  * Unit Test for PhoneInterfaceManager.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class PhoneInterfaceManagerTest extends TelephonyTestBase {
     @Rule
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -121,6 +123,8 @@
         mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED).commit();
         mSharedPreferences.edit().remove(Phone.PREF_NULL_CIPHER_NOTIFICATIONS_ENABLED).commit();
 
+        // Trigger sInstance restore in tearDown, after PhoneInterfaceManager.init.
+        replaceInstance(PhoneInterfaceManager.class, "sInstance", null, null);
         // Note that PhoneInterfaceManager is a singleton. Calling init gives us a handle to the
         // global singleton, but the context that is passed in is unused if the phone app is already
         // alive on a test devices. You must use the spy to mock behavior. Mocks stemming from the
@@ -503,7 +507,7 @@
         doNothing().when(mPhoneInterfaceManager).enforceModifyPermission();
 
         // FEATURE_TELEPHONY_CALLING
-        mPhoneInterfaceManager.handlePinMmiForSubscriber(1, "123456789");
+        mPhoneInterfaceManager.getVoiceActivationState(1, "com.test.package");
 
         // FEATURE_TELEPHONY_RADIO_ACCESS
         mPhoneInterfaceManager.toggleRadioOnOffForSubscriber(1);
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
index 11f982e..8963717 100644
--- a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
+++ b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
@@ -20,6 +20,7 @@
 import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_DISABLED;
 import static com.android.phone.satellite.entitlement.SatelliteEntitlementResult.SATELLITE_ENTITLEMENT_STATUS_ENABLED;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -46,18 +47,16 @@
 import android.net.NetworkCapabilities;
 import android.net.wifi.WifiInfo;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Looper;
-import android.os.Message;
 import android.os.PersistableBundle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
 import android.util.Pair;
 
 import androidx.annotation.NonNull;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.ExponentialBackoff;
@@ -87,7 +86,8 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
 public class SatelliteEntitlementControllerTest extends TelephonyTestBase {
     private static final String TAG = "SatelliteEntitlementControllerTest";
     private static final int SUB_ID = 0;
@@ -101,10 +101,8 @@
     private static final int CMD_RETRY_QUERY_ENTITLEMENT = 2;
     private static final int CMD_SIM_REFRESH = 3;
     private static final int MAX_RETRY_COUNT = 5;
-    @Mock
-    CarrierConfigManager mCarrierConfigManager;
-    @Mock
-    ConnectivityManager mConnectivityManager;
+    @Mock CarrierConfigManager mCarrierConfigManager;
+    @Mock ConnectivityManager mConnectivityManager;
     @Mock Network mNetwork;
     @Mock TelephonyManager mTelephonyManager;
     @Mock SubscriptionManagerService mMockSubscriptionManagerService;
@@ -118,6 +116,7 @@
     private TestableLooper mTestableLooper;
     private List<Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener>>
             mCarrierConfigChangedListenerList = new ArrayList<>();
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -129,14 +128,8 @@
         replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
         doReturn(Mockito.mock(PersistAtomsStorage.class)).when(mMetricsCollector).getAtomsStorage();
 
-        HandlerThread handlerThread = new HandlerThread("SatelliteEntitlementController");
-        handlerThread.start();
-        mHandler = new Handler(handlerThread.getLooper()) {
-            @Override
-            public void handleMessage(Message msg) {
-            }
-        };
-        mTestableLooper = new TestableLooper(mHandler.getLooper());
+        mTestableLooper = TestableLooper.get(this);
+        mHandler = new Handler(mTestableLooper.getLooper());
         doReturn(Context.TELEPHONY_SERVICE).when(mContext).getSystemServiceName(
                 TelephonyManager.class);
         doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
@@ -167,9 +160,8 @@
                 Context.CONNECTIVITY_SERVICE);
         doReturn(mNetwork).when(mConnectivityManager).getActiveNetwork();
         doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
-        mSatelliteEntitlementController = new TestSatelliteEntitlementController(mContext,
-                mHandler.getLooper(), mSatelliteEntitlementApi);
-        mSatelliteEntitlementController = spy(mSatelliteEntitlementController);
+        mSatelliteEntitlementController = spy(new TestSatelliteEntitlementController(mContext,
+                mTestableLooper.getLooper(), mSatelliteEntitlementApi));
         doReturn(mSatelliteEntitlementResult).when(
                 mSatelliteEntitlementApi).checkEntitlementStatus();
     }
@@ -181,7 +173,6 @@
 
     @Test
     public void testShouldStartQueryEntitlement() throws Exception {
-        logd("testShouldStartQueryEntitlement");
         doReturn(ACTIVE_SUB_ID).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
 
         // Verify don't start the query when KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL is false.
@@ -256,7 +247,6 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatus() throws Exception {
-        logd("testCheckSatelliteEntitlementStatus");
         setIsQueryAvailableTrue();
         // Verify don't call the checkSatelliteEntitlementStatus when getActiveSubIdList is empty.
         doReturn(new int[]{}).when(mMockSubscriptionManagerService).getActiveSubIdList(true);
@@ -347,7 +337,6 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatusWhenInternetConnected() throws Exception {
-        logd("testCheckSatelliteEntitlementStatusWhenInternetConnected");
         ConnectivityManager.NetworkCallback networkCallback =
                 (ConnectivityManager.NetworkCallback) getValue("mNetworkCallback");
         Network mockNetwork = mock(Network.class);
@@ -369,7 +358,6 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatusWhenCarrierConfigChanged() throws Exception {
-        logd("testCheckSatelliteEntitlementStatusWhenCarrierConfigChanged");
         // Verify the called the checkSatelliteEntitlementStatus when CarrierConfigChanged
         // occurred and Internet is connected.
         setInternetConnected(true);
@@ -386,7 +374,6 @@
 
     @Test
     public void testCheckWhenStartCmdIsReceivedDuringRetry() throws Exception {
-        logd("testCheckWhenStartCmdIsReceivedDuringRetry");
         // Verify that start cmd is ignored and retry is performed up to 5 times when start cmd
         // occurs during retries.
         setIsQueryAvailableTrue();
@@ -400,47 +387,47 @@
         verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
         // Verify that the retry count is 0 after receiving a 503 with retry-after header in
         // response.
-        assertTrue(retryCountPerSub.getOrDefault(SUB_ID, 0) == 0);
+        assertEquals(0, retryCountPerSub.getOrDefault(SUB_ID, 0).longValue());
 
         // Verify that the retry count is 1 for the second query when receiving a 503 with
         // retry-after header in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the retry count is 2 for the third query when receiving a 503 with
         // retry-after header in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+        assertEquals(2, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that start CMD is ignored during retries.
         sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+        assertEquals(2, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the retry count is 3 for the forth query when receiving a 503 with
         // retry-after header in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(4)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 3);
+        assertEquals(3, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the retry count is 4 for the fifth query when receiving a 503 with
         // retry-after header in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+        assertEquals(4, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that start CMD is ignored during retries.
         sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+        assertEquals(4, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the retry count is 5 for the sixth query when receiving a 503 with
         // retry-after header in response.
@@ -470,7 +457,6 @@
 
     @Test
     public void testCheckAfterInternetConnectionChangedDuringRetry() throws Exception {
-        logd("testCheckAfterInternetConnectionChangedDuringRetry");
         // Verify that the retry count is maintained even when internet connection is lost and
         // connected during retries, and that up to 5 retries are performed.
         setIsQueryAvailableTrue();
@@ -484,48 +470,48 @@
         verify(mSatelliteEntitlementApi, times(1)).checkEntitlementStatus();
         // Verify that the retry count is 0 after receiving a 503 with retry-after header in
         // response.
-        assertTrue(retryCountPerSub.getOrDefault(SUB_ID, 0) == 0);
+        assertEquals(0, retryCountPerSub.getOrDefault(SUB_ID, 0).longValue());
 
         // Verify that the retry count is 1 for the second query when receiving a 503 with
         // retry-after header in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that no query is executed and the retry count does not increase when internet
         // connection is lost during the second retry.
         setInternetConnected(false);
-        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
+        mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(2));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the query is started when internet connection is restored and that the
         // retry count does not increase.
         setInternetConnected(true);
-        logd("internet connected again");
+        Log.d(TAG, "internet connected again");
         sendMessage(CMD_START_QUERY_ENTITLEMENT, SUB_ID);
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
 
         // Verify that the retry count is increases after received a 503 with retry-after header
         // in response.
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(4)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 2);
+        assertEquals(2, retryCountPerSub.get(SUB_ID).longValue());
 
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(5)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 3);
+        assertEquals(3, retryCountPerSub.get(SUB_ID).longValue());
 
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(6)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 4);
+        assertEquals(4, retryCountPerSub.get(SUB_ID).longValue());
 
         mTestableLooper.moveTimeForward(TimeUnit.SECONDS.toMillis(1));
         mTestableLooper.processAllMessages();
@@ -553,7 +539,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error500() throws Exception {
-        logd("testStartQueryEntitlementStatus_error500");
         setIsQueryAvailableTrue();
         Map<Integer, Integer> retryCountPerSub =
                 (Map<Integer, Integer>) getValue("mRetryCountPerSub");
@@ -569,7 +554,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_retrySuccess() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_retrySuccess");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
         Map<Integer, Integer> retryCountPerSub =
@@ -597,7 +581,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_otherError_retrySuccess() throws Exception {
-        logd("testStartQueryEntitlementStatus_otherError_retrySuccess");
         setIsQueryAvailableTrue();
         Map<Integer, Integer> retryCountPerSub =
                 (Map<Integer, Integer>) getValue("mRetryCountPerSub");
@@ -622,7 +605,7 @@
         sendMessage(CMD_RETRY_QUERY_ENTITLEMENT, SUB_ID);
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(2)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
         // Verify don't call the onSatelliteEntitlementStatusUpdated.
         verify(mSatelliteController, never()).onSatelliteEntitlementStatusUpdated(anyInt(),
                 anyBoolean(), anyList(), anyList(), any());
@@ -637,14 +620,13 @@
         sendMessage(CMD_RETRY_QUERY_ENTITLEMENT, SUB_ID);
         mTestableLooper.processAllMessages();
         verify(mSatelliteEntitlementApi, times(3)).checkEntitlementStatus();
-        assertTrue(retryCountPerSub.get(SUB_ID) == 1);
+        assertEquals(1, retryCountPerSub.get(SUB_ID).longValue());
         verify(mSatelliteController).onSatelliteEntitlementStatusUpdated(eq(SUB_ID), eq(true),
                 eq(PLMN_ALLOWED_LIST), eq(PLMN_BARRED_LIST), any());
     }
 
     @Test
     public void testSatelliteEntitlementSupportedChangedFromSupportToNotSupport() throws Exception {
-        logd("testSatelliteEntitlementSupportedChangedFromSupportToNotSupport");
         setIsQueryAvailableTrue();
 
         // KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL changed from Support(entitlement status
@@ -699,7 +681,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_refreshStatus() throws Exception {
-        logd("testStartQueryEntitlementStatus_refreshStatus");
         setIsQueryAvailableTrue();
         mCarrierConfigBundle.putInt(
                 CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT, 1);
@@ -729,7 +710,6 @@
     @Test
     public void testStartQueryEntitlementStatus_internetDisconnectedAndConnectedAgain()
             throws Exception {
-        logd("testStartQueryEntitlementStatus_internetDisconnectedAndConnectedAgain");
         setIsQueryAvailableTrue();
 
         // Verify the query does not start if there is no internet connection.
@@ -757,7 +737,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_error500() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_error500");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
 
@@ -782,7 +761,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_otherError() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_otherError");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
 
@@ -820,7 +798,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_AfterSimRefresh() throws Exception {
-        logd("testStartQueryEntitlementStatus_AfterSimRefresh");
         setIsQueryAvailableTrue();
 
         // Verify the first query complete.
@@ -959,12 +936,8 @@
 
         @Override
         public SatelliteEntitlementApi getSatelliteEntitlementApi(int subId) {
-            logd("getSatelliteEntitlementApi");
+            Log.d(TAG, "getSatelliteEntitlementApi");
             return mInjectSatelliteEntitlementApi;
         }
     }
-
-    private static void logd(String log) {
-        Log.d(TAG, log);
-    }
 }
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
index 9895d1a..9592e1e 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/HeaderBlock.java
@@ -40,10 +40,26 @@
         int suffixBitCount = blockData.getUnsignedByte(offset++);
         int suffixRecordBitCount = blockData.getUnsignedByte(offset++);
         int suffixTableBlockIdOffset = blockData.getUnsignedByte(offset++);
-        boolean isAllowedList = (blockData.getUnsignedByte(offset) == TRUE);
-        mFileFormat = new SatS2RangeFileFormat(
-                dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
-                suffixRecordBitCount, isAllowedList);
+        boolean isAllowedList = (blockData.getUnsignedByte(offset++) == TRUE);
+
+
+        // Check if the block is in the original format or the enhanced format.
+        // If the offset is equal to the block data size, this block is in the original format.
+        // If the offset is less than the block data size, this block is an enhanced block, which
+        // has additional fields:
+        //  - the size of an entry value in bytes
+        //  - version number of header block
+        if (offset < blockData.getSize()) {
+            int entryValueSizeInBytes = blockData.getUnsignedByte(offset++);
+            int versionNumber = blockData.getInt(offset);
+            mFileFormat = new SatS2RangeFileFormat(
+                    dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
+                    suffixRecordBitCount, isAllowedList, entryValueSizeInBytes, versionNumber);
+        } else {
+            mFileFormat = new SatS2RangeFileFormat(
+                    dataS2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset,
+                    suffixRecordBitCount, isAllowedList);
+        }
     }
 
     /** Creates a {@link HeaderBlock} from low-level block data from a block file. */
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
index 39507aa..a335766 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileFormat.java
@@ -53,6 +53,10 @@
     /** The format version of the satellite S2 data file, read and written. */
     public static final int VERSION = 1;
 
+    private static final int DEFAULT_ENTRY_VALUE_SIZE_IN_BYTES = 0;
+    private static final int DEFAULT_VERSION_NUMBER = 0;
+    private static final int MAX_ENTRY_BYTE_COUNT = 4;
+
     private final int mDataS2Level;
 
     private final int mPrefixBitCount;
@@ -87,11 +91,28 @@
     private final boolean mIsAllowedList;
 
     /**
+     * Entry value size in bytes
+     */
+    private final int mEntryValueSizeInBytes;
+
+    /**
+     * Version number
+     */
+    private final int mVersionNumber;
+
+    public SatS2RangeFileFormat(int s2Level, int prefixBitCount, int suffixBitCount,
+            int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList) {
+        this(s2Level, prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, tableEntryBitCount,
+                isAllowedList, DEFAULT_ENTRY_VALUE_SIZE_IN_BYTES, DEFAULT_VERSION_NUMBER);
+    }
+
+    /**
      * Creates a new file format. This constructor validates the values against various hard-coded
      * constraints and will throw an {@link IllegalArgumentException} if they are not satisfied.
      */
     public SatS2RangeFileFormat(int s2Level, int prefixBitCount, int suffixBitCount,
-            int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList) {
+            int suffixTableBlockIdOffset, int tableEntryBitCount, boolean isAllowedList,
+            int entryValueSizeInBytes, int versionNumber) {
 
         Conditions.checkArgInRange("s2Level", s2Level, 0, MAX_S2_LEVEL);
 
@@ -180,6 +201,12 @@
         mSuffixTableBlockIdOffset = suffixTableBlockIdOffset;
 
         mIsAllowedList = isAllowedList;
+
+        Conditions.checkArgInRange("entryValueSizeInBytes", entryValueSizeInBytes, 0,
+                MAX_ENTRY_BYTE_COUNT);
+        mEntryValueSizeInBytes = entryValueSizeInBytes;
+
+        mVersionNumber = versionNumber;
     }
 
     /** Returns the S2 level of all geo data stored in the file. */
@@ -345,6 +372,18 @@
                 + "}";
     }
 
+    /**
+     * Returns the length of entry value in Bytes.
+     * @return the length of entry value
+     */
+    public int getEntryValueSizeInBytes() {
+        return mEntryValueSizeInBytes;
+    }
+
+    public int getVersionNumber() {
+        return mVersionNumber;
+    }
+
     @Override
     public String toString() {
         return "SatS2RangeFileFormat{"
@@ -359,6 +398,8 @@
                 + ", mSuffixTableBlockIdOffset=" + mSuffixTableBlockIdOffset
                 + ", mUnusedCellIdBitCount=" + mUnusedCellIdBitCount
                 + ", mIsAllowedList=" + mIsAllowedList
+                + ", mEntryValueSizeInBytes=" + mEntryValueSizeInBytes
+                + ", mVersionNumber=" + mVersionNumber
                 + '}';
     }
 
@@ -381,7 +422,9 @@
                 && mTableEntryMaxRangeLengthValue == that.mTableEntryMaxRangeLengthValue
                 && mSuffixTableBlockIdOffset == that.mSuffixTableBlockIdOffset
                 && mIsAllowedList == that.mIsAllowedList
-                && mUnusedCellIdBitCount == that.mUnusedCellIdBitCount;
+                && mUnusedCellIdBitCount == that.mUnusedCellIdBitCount
+                && mEntryValueSizeInBytes == that.mEntryValueSizeInBytes
+                && mVersionNumber == that.mVersionNumber;
     }
 
     @Override
@@ -389,7 +432,7 @@
         return Objects.hash(mDataS2Level, mPrefixBitCount, mMaxPrefixValue, mSuffixBitCount,
                 mMaxSuffixValue, mTableEntryBitCount, mTableEntryRangeLengthBitCount,
                 mTableEntryMaxRangeLengthValue, mSuffixTableBlockIdOffset, mIsAllowedList,
-                mUnusedCellIdBitCount);
+                mUnusedCellIdBitCount, mEntryValueSizeInBytes, mVersionNumber);
     }
 
     private void checkS2Level(String name, long cellId) {
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
index 88f1b2e..8c1466f 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
@@ -23,12 +23,12 @@
 import java.util.Objects;
 
 public final class SuffixTableRange extends S2LevelRange {
-    private static final int DEAFAULT_ENTRY_VALUE = -1;
+    private static final int DEFAULT_ENTRY_VALUE = -1;
     private final int mEntryValue;
 
     // For backward compatibility
     public SuffixTableRange(long startCellId, long endCellId) {
-        this(startCellId, endCellId, DEAFAULT_ENTRY_VALUE);
+        this(startCellId, endCellId, DEFAULT_ENTRY_VALUE);
     }
 
     public SuffixTableRange(long startCellId, long endCellId, int entryValue) {
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
index 2221b2c..14cb92f 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableSharedData.java
@@ -16,11 +16,13 @@
 
 package com.android.telephony.sats2range.read;
 
+import com.android.storage.block.read.TypedData;
 import com.android.storage.io.read.TypedInputStream;
 import com.android.storage.table.reader.Table;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -28,14 +30,98 @@
  * entries in the table and is required when interpreting the table's block data.
  */
 public final class SuffixTableSharedData {
-
+    public static final int INVALID_ENTRY_VALUE = -1;
     private final int mTablePrefix;
+    private final int mEntryValueSizeInBytes;
+    private final int mNumberOfEntryValues;
+    private final int mHeaderByteOffsetToRead;
+    private List<Integer> mEntryValuesToWrite = List.of(); // This is used for write path
+    private final TypedData mSharedDataToRead; // This is used for read path
 
     /**
      * Creates a {@link SuffixTableSharedData}. See also {@link #fromBytes(byte[])}.
      */
     public SuffixTableSharedData(int tablePrefix) {
         mTablePrefix = tablePrefix;
+        mEntryValueSizeInBytes = 0;
+        mNumberOfEntryValues = 0;
+        mHeaderByteOffsetToRead = 0;
+        mSharedDataToRead = null;
+    }
+
+    /**
+     * This constructor is used for write path
+     */
+    public SuffixTableSharedData(int tablePrefix, List<Integer> entryValues,
+            SatS2RangeFileFormat fileFormat) {
+        mSharedDataToRead = null;
+        mTablePrefix = tablePrefix;
+        mNumberOfEntryValues = entryValues.size();
+        mEntryValuesToWrite = entryValues;
+        mEntryValueSizeInBytes = fileFormat.getEntryValueSizeInBytes();
+        mHeaderByteOffsetToRead = 0;
+    }
+
+    /**
+     * This constructor is used for read path
+     */
+    public SuffixTableSharedData(TypedData sharedDataToRead, SatS2RangeFileFormat fileFormat) {
+        mSharedDataToRead = Objects.requireNonNull(sharedDataToRead);
+        int offset = 0;
+        // extract prefix value
+        mTablePrefix = mSharedDataToRead.getInt(offset);
+        offset += Integer.BYTES;
+
+        // If the size of shared data is greater than the offset, extract the number of entry
+        // values.
+        if ((offset + Integer.BYTES) < mSharedDataToRead.getSize()) {
+            mNumberOfEntryValues = mSharedDataToRead.getInt(offset);
+            mHeaderByteOffsetToRead = offset + Integer.BYTES;
+            mEntryValueSizeInBytes = fileFormat.getEntryValueSizeInBytes();
+        } else {
+            mNumberOfEntryValues = 0;
+            mHeaderByteOffsetToRead = offset;
+            mEntryValueSizeInBytes = 0;
+        }
+    }
+
+    /**
+     * This is used for read path
+     */
+    public static SuffixTableSharedData fromTypedData(TypedData sharedData,
+            SatS2RangeFileFormat fileFormat) {
+        return new SuffixTableSharedData(sharedData, fileFormat);
+    }
+
+    /**
+     * Reads the entry value at a specific position in the byte buffer and returns it.
+     *
+     * @param entryIndex The index of entry to be read.
+     * @return entry value (integer) read from the byte buffer.
+     */
+    public int getEntryValue(int entryIndex) {
+        if (mSharedDataToRead == null || entryIndex < 0 || mNumberOfEntryValues == 0) {
+            return INVALID_ENTRY_VALUE;
+        }
+
+        if (mNumberOfEntryValues == 1) {
+            entryIndex = 0;
+        }
+
+        int offset;
+        if (entryIndex < mNumberOfEntryValues) {
+            // offset = table prefix(4) + entry value count(4) + size of entry * entry index
+            offset = mHeaderByteOffsetToRead + (mEntryValueSizeInBytes * entryIndex);
+        } else {
+            return INVALID_ENTRY_VALUE;
+        }
+
+        return getValueInternal(mSharedDataToRead, mEntryValueSizeInBytes, offset);
+    }
+
+    // Entry lists to be written to a byte buffer.
+    public List<Integer> getEntryValuesToWrite() {
+        return mEntryValuesToWrite;
     }
 
     /**
@@ -46,6 +132,20 @@
         return mTablePrefix;
     }
 
+    /**
+     * Returns the number of entry values.
+     */
+    public int getNumberOfEntryValues() {
+        return mNumberOfEntryValues;
+    }
+
+    /**
+     * Returns the size of entry value in Bytes.
+     */
+    public int getEntryValueSizeInBytes() {
+        return mEntryValueSizeInBytes;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -55,18 +155,22 @@
             return false;
         }
         SuffixTableSharedData that = (SuffixTableSharedData) o;
-        return mTablePrefix == that.mTablePrefix;
+        return mTablePrefix == that.mTablePrefix
+                && mNumberOfEntryValues == that.mNumberOfEntryValues
+                && mEntryValuesToWrite.equals(that.mEntryValuesToWrite);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mTablePrefix);
+        return Objects.hash(mTablePrefix, mNumberOfEntryValues, mEntryValuesToWrite);
     }
 
     @Override
     public String toString() {
         return "SuffixTableSharedData{"
                 + "mTablePrefix=" + mTablePrefix
+                + "mNumberOfEntries=" + mNumberOfEntryValues
+                + "mEntryValuesToWrite=" + mEntryValuesToWrite
                 + '}';
     }
 
@@ -82,4 +186,21 @@
             throw new RuntimeException(e);
         }
     }
+
+    private int getValueInternal(TypedData buffer, int valueSizeBytes, int byteOffset) {
+        if (byteOffset < 0) {
+            throw new IllegalArgumentException(
+                    "byteOffset=" + byteOffset + " must not be negative");
+        }
+
+        // High bytes read first.
+        int value = 0;
+        int bytesRead = 0;
+        while (bytesRead++ < valueSizeBytes) {
+            value <<= Byte.SIZE;
+            value |= buffer.getUnsignedByte(byteOffset++);
+        }
+
+        return value;
+    }
 }
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
index 80ef467..65da1e4 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileFormatTest.java
@@ -67,10 +67,12 @@
         int suffixBitCount = 16;
         int suffixTableBlockIdOffset = 5;
         int suffixTableEntryBitCount = 24;
+        int suffixTableEntryValueSizeInBytes = 4;
+        int versionNumber = 2;
         boolean isAllowedList = false;
         SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
                 prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
-                isAllowedList);
+                isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
 
         assertEquals(2, satS2RangeFileFormat.calculateRangeLength(
                 cellId(s2Level, 0, 0), cellId(s2Level, 0, 2)));
@@ -92,9 +94,11 @@
         int suffixTableBlockIdOffset = 5;
         int suffixTableEntryBitCount = 24;
         boolean isAllowedList = true;
+        int suffixTableEntryValueSizeInBytes = 4;
+        int versionNumber = 2;
         SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
                 prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
-                isAllowedList);
+                isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
 
         // Too many bits for prefixValue
         assertThrows(IllegalArgumentException.class,
@@ -127,9 +131,11 @@
         int suffixTableBlockIdOffset = 5;
         int suffixTableEntryBitCount = 24;
         boolean isAllowedList = true;
+        int suffixTableEntryValueSizeInBytes = 4;
+        int versionNumber = 2;
         SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
                 prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
-                isAllowedList);
+                isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
 
         assertEquals(0, satS2RangeFileFormat.extractFaceIdFromPrefix(0b00000000000));
         assertEquals(5, satS2RangeFileFormat.extractFaceIdFromPrefix(0b10100000000));
@@ -147,9 +153,11 @@
         int suffixTableBlockIdOffset = 5;
         int suffixTableEntryBitCount = 24;
         boolean isAllowedList = true;
+        int suffixTableEntryValueSizeInBytes = 4;
+        int versionNumber = 2;
         SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
                 prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
-                isAllowedList);
+                isAllowedList, suffixTableEntryValueSizeInBytes, versionNumber);
 
         // Too many bits for rangeLength
         assertThrows(IllegalArgumentException.class,
@@ -161,6 +169,33 @@
         assertTrue(satS2RangeFileFormat.isAllowedList());
     }
 
+    @Test
+    public void extractEntryValueByteCount() {
+        int s2Level = 12;
+        int prefixBitCount = 11;
+        int suffixBitCount = 16;
+        int suffixTableBlockIdOffset = 5;
+        int suffixTableEntryBitCount = 24;
+        boolean isAllowedList = true;
+        final int[] suffixTableEntryValueSizeInBytes = {5};
+        int versionNumber = 1;
+
+        // Table entry byte count exceeds BYTE range.
+        assertThrows(IllegalArgumentException.class,
+                () -> new SatS2RangeFileFormat(s2Level, prefixBitCount, suffixBitCount,
+                        suffixTableBlockIdOffset, suffixTableEntryBitCount, isAllowedList,
+                        suffixTableEntryValueSizeInBytes[0], versionNumber));
+
+        suffixTableEntryValueSizeInBytes[0] = 1;
+        SatS2RangeFileFormat satS2RangeFileFormat = new SatS2RangeFileFormat(s2Level,
+                prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
+                isAllowedList, suffixTableEntryValueSizeInBytes[0], versionNumber);
+
+        assertEquals(suffixTableEntryValueSizeInBytes[0],
+                satS2RangeFileFormat.getEntryValueSizeInBytes());
+        assertEquals(versionNumber, satS2RangeFileFormat.getVersionNumber());
+    }
+
     private static int maxValForBits(int bits) {
         return intPow2(bits) - 1;
     }
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
index 2baefa9..ee21626 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableSharedDataTest.java
@@ -18,11 +18,18 @@
 
 import static org.junit.Assert.assertEquals;
 
+import com.android.storage.block.read.BlockData;
+import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SuffixTableSharedData;
 import com.android.telephony.sats2range.write.SuffixTableSharedDataWriter;
 
 import org.junit.Test;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /** Tests for {@link SuffixTableSharedData} and {@link SuffixTableSharedDataWriter}. */
 public class SuffixTableSharedDataTest {
     @Test
@@ -33,5 +40,106 @@
 
         assertEquals(sharedData, SuffixTableSharedData.fromBytes(bytes));
     }
-}
 
+    @Test
+    public void testSuffixTableSharedDataWithEntryValues() {
+        int prefix = 321;
+        int entryValueSizeInBytes = 1;
+        List<Integer> entryValues = new ArrayList<>(Arrays.asList(0x01, 0x7F, 0xFF));
+        int versionNumber = 1;
+
+        // Verify whether fromTypedData returns correct SuffixTableSharedData when entryByte is 1
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+
+        // Verify when entryValueSizeInBytes is 2
+        entryValueSizeInBytes = 2;
+        entryValues = new ArrayList<>(Arrays.asList(0x001, 0x5FFF, 0xAFFF, 0xFFFF));
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+
+        // Verify when entryValueSizeInBytes is 3
+        entryValueSizeInBytes = 3;
+        entryValues = new ArrayList<>(
+                Arrays.asList(0x000001, 0x4FFFFF, 0x8FFFFF, 0xBFFFFF, 0xFFFFFF));
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+
+        // Verify when entryValueSizeInBytes is 4, max int value is 0x7FFFFFFF.
+        // ConfigID is supported up to 0x7FFFFFFF for now.
+        entryValueSizeInBytes = 4;
+        entryValues = new ArrayList<>(
+                Arrays.asList(0x00000001, 0x2FFFFFFF, 0x3FFFFFFF, 0x4FFFFFFF, 0x5FFFFFFF,
+                        0x6FFFFFFF, 0x7FFFFFFF));
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+
+        // Verify when every entry has same value.
+        entryValues = new ArrayList<>(
+                Arrays.asList(0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF,
+                        0x3FFFFFFF, 0x3FFFFFFF));
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+
+        // Verify when entry is empty
+        // entryValueSizeInBytes is set as 4, but there is no entry list
+        entryValues = new ArrayList<>(List.of());
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+        // entryValueSizeInBytes is 0, no entry list
+        entryValueSizeInBytes = 0;
+        verifySharedData(prefix, entryValueSizeInBytes, entryValues.size(), entryValues,
+                versionNumber);
+    }
+
+    private BlockData createBlockedDataFromByteBuffer(int prefix,
+            List<Integer> entryValues, SatS2RangeFileFormat fileFormat) {
+        SuffixTableSharedData sharedDataToWrite = new SuffixTableSharedData(prefix, entryValues,
+                fileFormat);
+        ByteBuffer byteBuffer = ByteBuffer.wrap(
+                SuffixTableSharedDataWriter.toBytes(sharedDataToWrite));
+        return new BlockData(byteBuffer.asReadOnlyBuffer());
+    }
+
+    private void verifySharedData(int expectedTablePrefix, int expectedEntryValueSizeInBytes,
+            int expectedNumberOfEntryValues, List<Integer> expectedEntryValues, int versionNumber) {
+        SatS2RangeFileFormat fileFormat = createSatS2RangeFileFormat(expectedEntryValueSizeInBytes,
+                versionNumber);
+        BlockData blockData = createBlockedDataFromByteBuffer(
+                expectedTablePrefix, expectedEntryValues, fileFormat);
+        SuffixTableSharedData sharedData = SuffixTableSharedData.fromTypedData(blockData,
+                fileFormat);
+
+        assertEquals(expectedTablePrefix, sharedData.getTablePrefix());
+        if (!expectedEntryValues.isEmpty()) {
+            assertEquals(expectedEntryValueSizeInBytes, sharedData.getEntryValueSizeInBytes());
+        } else {
+            assertEquals(0, sharedData.getEntryValueSizeInBytes());
+        }
+
+        // If every entry has same value, block data contains only 1 entry info
+        if (expectedEntryValues.stream().distinct().count() == 1) {
+            assertEquals(3 * Integer.BYTES, blockData.getSize());
+            // Verify whether the entry value count has been set to 1.
+            assertEquals(1, sharedData.getNumberOfEntryValues());
+        } else {
+            assertEquals(expectedNumberOfEntryValues, sharedData.getNumberOfEntryValues());
+        }
+        for (int i = 0; i < expectedNumberOfEntryValues; i++) {
+            assertEquals((int) expectedEntryValues.get(i), sharedData.getEntryValue(i));
+        }
+    }
+
+    private SatS2RangeFileFormat createSatS2RangeFileFormat(int entryByteCount, int versionNumber) {
+        int s2Level = 12;
+        int prefixBitCount = 11;
+        int suffixBitCount = 16;
+        int suffixTableBlockIdOffset = 5;
+        int suffixTableEntryBitCount = 24;
+        boolean isAllowedList = true;
+
+        return new SatS2RangeFileFormat(s2Level,
+                prefixBitCount, suffixBitCount, suffixTableBlockIdOffset, suffixTableEntryBitCount,
+                isAllowedList, entryByteCount, versionNumber);
+    }
+}
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
index d4e9310..0435922 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/HeaderBlockWriter.java
@@ -63,6 +63,8 @@
             tos.writeUnsignedByte(mFileFormat.getSuffixTableBlockIdOffset());
             tos.writeUnsignedByte(mFileFormat.isAllowedList()
                     ? HeaderBlock.TRUE : HeaderBlock.FALSE);
+            tos.writeUnsignedByte(mFileFormat.getEntryValueSizeInBytes());
+            tos.writeInt(mFileFormat.getVersionNumber());
         }
 
         FileChannel fileChannel = FileChannel.open(mFile.toPath(), StandardOpenOption.READ);
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
index 5499148..a739e5e 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableSharedDataWriter.java
@@ -21,21 +21,37 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.List;
 
 /**
  * Converts a {@link SuffixTableSharedData} to a byte[] for writing.
  * See also {@link SuffixTableSharedData#fromBytes(byte[])}.
  */
 public final class SuffixTableSharedDataWriter {
-
+    private static final int BUFFER_SIZE = (int) Math.pow(2, 20);
     private SuffixTableSharedDataWriter() {
     }
 
     /** Returns the byte[] for the supplied {@link SuffixTableSharedData} */
     public static byte[] toBytes(SuffixTableSharedData suffixTableSharedData) {
+        int entryValueSizeInBytes = suffixTableSharedData.getEntryValueSizeInBytes();
+        List<Integer> entryValues = suffixTableSharedData.getEntryValuesToWrite();
+        // If every entry has same value, compress to save memory
+        int numberOfEntryValues =
+                entryValues.stream().distinct().count() == 1 ? 1 : entryValues.size();
+
         try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                TypedOutputStream tos = new TypedOutputStream(baos)) {
+                TypedOutputStream tos = new TypedOutputStream(baos, BUFFER_SIZE)) {
             tos.writeInt(suffixTableSharedData.getTablePrefix());
+
+            if (entryValueSizeInBytes > 0 && !entryValues.isEmpty()) {
+                tos.writeInt(numberOfEntryValues);
+                for (int i = 0; i < numberOfEntryValues; i++) {
+                    // ConfigId is supported up to 0x7FFFFFFF
+                    tos.writeVarByteValue(entryValueSizeInBytes, entryValues.get(i));
+                }
+            }
+
             tos.flush();
             return baos.toByteArray();
         } catch (IOException e) {