Merge "Fix NPE at RadioInfo" into main
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
index 4f650a0..b3c8976 100644
--- a/assets/CarrierRestrictionOperatorDetails.json
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -7,5 +7,8 @@
   "com.comcast.mobile.mxs":{"carrierIds": [2032,2532,2556],"callerSHA256Ids":["914C26403B57D2D482359FC235CC825AD00D52B0121C18EF2B2B9D4DDA4B8996"]},
   "com.xfinity.digitalhome": {"carrierIds": [2032,2532,2556],"callerSHA256Ids":["31b4c17315c2269040d535f7b6a79cf4d11517c664d9de8f1ddf4f8a785aad47"]},
   "com.xfinity.digitalhome.debug":{"carrierIds": [2032,2532,2556],"callerSHA256Ids":["c9133e8168f97573c8c567f46777dff74ade0c015ecf2c5e91be3e4e76ddcae2"]},
-  "com.xfinity.dh.xm.app": {"carrierIds": [2032,2532,2556],"callerSHA256Ids":["c9133e8168f97573c8c567f46777dff74ade0c015ecf2c5e91be3e4e76ddcae2"]}
+  "com.xfinity.dh.xm.app": {"carrierIds": [2032,2532,2556],"callerSHA256Ids":["c9133e8168f97573c8c567f46777dff74ade0c015ecf2c5e91be3e4e76ddcae2"]},
+  "com.tmobile.tmte": {"carrierIds": [1],"callerSHA256Ids":["3D:1A:4B:EF:6E:E7:AF:7D:34:D1:20:E7:B1:AA:C0:DD:24:55:85:DE:62:37:CF:10:0F:68:33:3A:FA:CF:F5:62"]},
+  "com.tmobile.tuesdays": {"carrierIds": [1],"callerSHA256Ids":["3D:1A:4B:EF:6E:E7:AF:7D:34:D1:20:E7:B1:AA:C0:DD:24:55:85:DE:62:37:CF:10:0F:68:33:3A:FA:CF:F5:62","92:B5:F8:11:7F:BD:9B:D5:73:8F:F1:68:A4:FA:12:CB:E2:84:BE:83:4E:DE:1A:7B:B4:4D:D8:45:5B:A1:59:20"]},
+  "com.tmobile.pr.mytmobile": {"carrierIds": [1],"callerSHA256Ids":["92:B5:F8:11:7F:BD:9B:D5:73:8F:F1:68:A4:FA:12:CB:E2:84:BE:83:4E:DE:1A:7B:B4:4D:D8:45:5B:A1:59:20"]}
 }
\ No newline at end of file
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/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index bd90a9d..440c39d 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -6641,6 +6641,8 @@
      * Sets the ImsService Package Name that Telephony will bind to.
      *
      * @param slotIndex the slot ID that the ImsService should bind for.
+     * @param userId the user ID that the ImsService should bind for or {@link UserHandle#USER_NULL}
+     *               if there is no preference.
      * @param isCarrierService true if the ImsService is the carrier override, false if the
      *         ImsService is the device default ImsService.
      * @param featureTypes An integer array of feature types associated with a packageName.
@@ -6648,7 +6650,7 @@
      *                    with.
      * @return true if setting the ImsService to bind to succeeded, false if it did not.
      */
-    public boolean setBoundImsServiceOverride(int slotIndex, boolean isCarrierService,
+    public boolean setBoundImsServiceOverride(int slotIndex, int userId, boolean isCarrierService,
             int[] featureTypes, String packageName) {
         TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setBoundImsServiceOverride");
         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
@@ -6660,12 +6662,8 @@
                 // may happen if the device does not support IMS.
                 return false;
             }
-            Map<Integer, String> featureConfig = new HashMap<>();
-            for (int featureType : featureTypes) {
-                featureConfig.put(featureType, packageName);
-            }
-            return mImsResolver.overrideImsServiceConfiguration(slotIndex, isCarrierService,
-                    featureConfig);
+            return mImsResolver.overrideImsServiceConfiguration(packageName, slotIndex, userId,
+                    isCarrierService, featureTypes);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13204,11 +13202,14 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             if (enableSatellite) {
+                String caller = "PIM:requestSatelliteEnabled";
                 ResultReceiver resultReceiver = new ResultReceiver(mMainThreadHandler) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
                         Log.d(LOG_TAG, "Satellite access restriction resultCode=" + resultCode
                                 + ", resultData=" + resultData);
+                        mSatelliteController.decrementResultReceiverCount(caller);
+
                         boolean isAllowed = false;
                         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(
                                 callback::accept);
@@ -13241,6 +13242,7 @@
                 };
                 mSatelliteAccessController.requestIsCommunicationAllowedForCurrentLocation(
                         resultReceiver, true);
+                mSatelliteController.incrementResultReceiverCount(caller);
             } else {
                 // No need to check if satellite is allowed at current location when disabling
                 // satellite
@@ -13723,6 +13725,29 @@
     }
 
     /**
+     * Request to get satellite access configuration for the current location.
+     *
+     * @param result The result receiver that returns the satellite access configuration
+     *               for the current location if the request is successful or an error code
+     *               if the request failed.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void requestSatelliteAccessConfigurationForCurrentLocation(
+            @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission(
+                "requestSatelliteAccessConfigurationForCurrentLocation");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mSatelliteAccessController
+                    .requestSatelliteAccessConfigurationForCurrentLocation(result);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * Request to get the time after which the satellite will be visible.
      *
      * @param result The result receiver that returns the time after which the satellite will
@@ -14725,6 +14750,24 @@
         }
     }
 
+
+    /**
+     * Inform whether application supports NTN SMS in satellite mode.
+     *
+     * This method is used by default messaging application to inform framework whether it supports
+     * NTN SMS or not.
+     *
+     * @param ntnSmsSupported {@code true} If application supports NTN SMS, else {@code false}.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     */
+    @Override
+    public void setNtnSmsSupported(boolean ntnSmsSupported) {
+        enforceSatelliteCommunicationPermission("setNtnSmsSupported");
+        enforceSendSmsPermission();
+        mSatelliteController.setNtnSmsSupportedByMessagesApp(ntnSmsSupported);
+    }
+
     /**
      * This API can be used by only CTS to override the cached value for the device overlay config
      * value :
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 840f961..5ea1304 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -526,11 +526,14 @@
     private void onHelpIms() {
         PrintWriter pw = getOutPrintWriter();
         pw.println("IMS Commands:");
-        pw.println("  ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
+        pw.println("  ims set-ims-service [-s SLOT_ID] [-u USER_ID] (-c | -d | -f) PACKAGE_NAME");
         pw.println("    Sets the ImsService defined in PACKAGE_NAME to to be the bound");
         pw.println("    ImsService. Options are:");
         pw.println("      -s: the slot ID that the ImsService should be bound for. If no option");
         pw.println("          is specified, it will choose the default voice SIM slot.");
+        pw.println("      -u: the user ID that the ImsService should be bound on. If no option");
+        pw.println("          is specified, the SYSTEM user ID will be preferred followed by the");
+        pw.println("          current user ID if they are different");
         pw.println("      -c: Override the ImsService defined in the carrier configuration.");
         pw.println("      -d: Override the ImsService defined in the device overlay.");
         pw.println("      -f: Set the feature that this override if for, if no option is");
@@ -1353,12 +1356,22 @@
     private int handleImsSetServiceCommand() {
         PrintWriter errPw = getErrPrintWriter();
         int slotId = getDefaultSlot();
+        int userId = UserHandle.USER_NULL; // By default, set no userId constraint
         Boolean isCarrierService = null;
         List<Integer> featuresList = new ArrayList<>();
 
         String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
+                case "-u": {
+                    try {
+                        userId = Integer.parseInt(getNextArgRequired());
+                    } catch (NumberFormatException e) {
+                        errPw.println("ims set-ims-service requires an integer as a USER_ID");
+                        return -1;
+                    }
+                    break;
+                }
                 case "-s": {
                     try {
                         slotId = Integer.parseInt(getNextArgRequired());
@@ -1414,17 +1427,17 @@
             for (int i = 0; i < featuresList.size(); i++) {
                 featureArray[i] = featuresList.get(i);
             }
-            boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
+            boolean result = mInterface.setBoundImsServiceOverride(slotId, userId, isCarrierService,
                     featureArray, packageName);
             if (VDBG) {
-                Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
+                Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " -u " + userId + " "
                         + (isCarrierService ? "-c " : "-d ")
                         + "-f " + featuresList + " "
                         + packageName + ", result=" + result);
             }
             getOutPrintWriter().println(result);
         } catch (RemoteException e) {
-            Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
+            Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " -u " + userId + " "
                     + (isCarrierService ? "-c " : "-d ")
                     + "-f " + featuresList + " "
                     + packageName + ", error" + e.getMessage());
diff --git a/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java b/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
index c5ecfd9..845ff18 100644
--- a/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
@@ -15,15 +15,11 @@
  */
 package com.android.phone.satellite.accesscontrol;
 
-import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.telephony.Rlog;
 
 import com.android.internal.telephony.flags.FeatureFlags;
-import com.android.storage.s2.S2LevelRange;
-
 import com.android.telephony.sats2range.read.SatS2RangeFileReader;
 import com.android.telephony.sats2range.read.SuffixTableRange;
 
@@ -178,18 +174,22 @@
 
     @Override
     @Nullable
-    public Integer getRegionalConfigIdForLocation(LocationToken locationToken)
+    public Integer getRegionalConfigIdForLocation(@NonNull LocationToken locationToken)
             throws IOException {
         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
             logd("getAccessControlConfigIdForLocation: carrierRoamingNbIotNtn is disabled");
             return null;
         }
 
-        if (!isSatCommunicationAllowedAtLocation(locationToken)) {
-            logd("getRegionalConfigIdForLocation: isSatCommunicationAllowedAtLocation is false");
-            return null;
+        if (locationToken instanceof LocationTokenImpl locationTokenImpl) {
+            return getRegionalConfigIdForLocation(locationTokenImpl.getS2CellId());
+        } else {
+            throw new IllegalArgumentException("Unknown locationToken=" + locationToken);
         }
+    }
 
-        return DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+    private Integer getRegionalConfigIdForLocation(long s2CellId) throws IOException {
+        SuffixTableRange entry = mSatS2RangeFileReader.findEntryByCellId(s2CellId);
+        return (entry == null) ? null : entry.getEntryValue();
     }
 }
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 49edf6a..5f60291 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -16,6 +16,7 @@
 
 package com.android.phone.satellite.accesscontrol;
 
+import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ACCESS_CONFIGURATION;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED;
@@ -24,6 +25,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
@@ -78,6 +80,7 @@
 import android.telephony.satellite.ISatelliteDisallowedReasonsCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
 import android.telephony.satellite.ISatelliteSupportedStateCallback;
+import android.telephony.satellite.SatelliteAccessConfiguration;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.text.TextUtils;
@@ -116,6 +119,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -160,6 +164,8 @@
     protected static final int EVENT_LOCATION_SETTINGS_ENABLED = 6;
 
     public static final int DEFAULT_REGIONAL_SATELLITE_CONFIG_ID = 0;
+    public static final int UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID = -1;
+
 
     private static final String KEY_AVAILABLE_NOTIFICATION_SHOWN = "available_notification_shown";
     private static final String KEY_UNAVAILABLE_NOTIFICATION_SHOWN =
@@ -260,11 +266,11 @@
     private long mOverriddenLocationFreshDurationNanos;
     @GuardedBy("mLock")
     @NonNull
-    private final Map<SatelliteOnDeviceAccessController.LocationToken, Boolean>
+    private final Map<SatelliteOnDeviceAccessController.LocationToken, Integer>
             mCachedAccessRestrictionMap = new LinkedHashMap<>() {
         @Override
         protected boolean removeEldestEntry(
-                Entry<SatelliteOnDeviceAccessController.LocationToken, Boolean> eldest) {
+                Entry<SatelliteOnDeviceAccessController.LocationToken, Integer> eldest) {
             return size() > MAX_CACHE_SIZE;
         }
     };
@@ -277,7 +283,15 @@
     private Location mFreshLastKnownLocation = null;
     @GuardedBy("mLock")
     @Nullable
-    private Integer mRegionalConfigId = null;
+    protected Integer mRegionalConfigId = null;
+    @GuardedBy("mLock")
+    @Nullable
+    protected Integer mNewRegionalConfigId = null;
+
+    /** Key: Config ID; Value: SatelliteAccessConfiguration */
+    @NonNull
+    private HashMap<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap =
+            new HashMap<>();
 
     /** These are used for CTS test */
     private Path mCtsSatS2FilePath = null;
@@ -425,6 +439,9 @@
                 handleIsSatelliteSupportedResult(resultCode, resultData);
             }
         };
+        mSatelliteController.incrementResultReceiverCount(
+                "SAC:mInternalSatelliteSupportedResultReceiver");
+
         mInternalSatelliteProvisionedResultReceiver = new ResultReceiver(this) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -442,13 +459,16 @@
             public void onSatelliteSupportedStateChanged(boolean isSupported) {
                 logd("onSatelliteSupportedStateChanged: isSupported=" + isSupported);
                 if (isSupported) {
+                    final String caller = "SAC:onSatelliteSupportedStateChanged";
                     requestIsCommunicationAllowedForCurrentLocation(
                             new ResultReceiver(null) {
                                 @Override
                                 protected void onReceiveResult(int resultCode, Bundle resultData) {
+                                    mSatelliteController.decrementResultReceiverCount(caller);
                                     // do nothing
                                 }
                             }, false);
+                    mSatelliteController.incrementResultReceiverCount(caller);
                     if (mSatelliteDisallowedReasons.contains(
                             Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED))) {
                         mSatelliteDisallowedReasons.remove(
@@ -473,13 +493,16 @@
             public void onSatelliteProvisionStateChanged(boolean isProvisioned) {
                 logd("onSatelliteProvisionStateChanged: isProvisioned=" + isProvisioned);
                 if (isProvisioned) {
+                    final String caller = "SAC:onSatelliteProvisionStateChanged";
                     requestIsCommunicationAllowedForCurrentLocation(
                             new ResultReceiver(null) {
                                 @Override
                                 protected void onReceiveResult(int resultCode, Bundle resultData) {
+                                    mSatelliteController.decrementResultReceiverCount(caller);
                                     // do nothing
                                 }
                             }, false);
+                    mSatelliteController.incrementResultReceiverCount(caller);
                     if (mSatelliteDisallowedReasons.contains(
                             SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED)) {
                         mSatelliteDisallowedReasons.remove(
@@ -522,6 +545,13 @@
                 mCurrentSatelliteAllowedState = isAllowed;
                 notifySatelliteCommunicationAllowedStateChanged(isAllowed);
                 mControllerMetricsStats.reportAllowedStateChanged();
+                if (!isAllowed) {
+                    synchronized (mLock) {
+                        plogd("updateCurrentSatelliteAllowedState : set mNewRegionalConfigId null");
+                        mNewRegionalConfigId = null;
+                    }
+                }
+                updateRegionalConfigId();
             }
         }
     }
@@ -591,6 +621,68 @@
         mAccessControllerMetricsStats.setTriggeringEvent(TRIGGERING_EVENT_EXTERNAL_REQUEST);
         sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED,
                 new Pair<>(mSatelliteController.getSelectedSatelliteSubId(), result));
+        mSatelliteController.incrementResultReceiverCount(
+                "SAC:requestIsCommunicationAllowedForCurrentLocation");
+    }
+
+    /**
+     * Request to get satellite access configuration for the current location.
+     *
+     * @param result The result receiver that returns satellite access configuration
+     *               for the current location if the request is successful or an error code
+     *               if the request failed.
+     */
+    public void requestSatelliteAccessConfigurationForCurrentLocation(
+            @NonNull ResultReceiver result) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            plogd("carrierRoamingNbIotNtnFlag is disabled");
+            result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+            return;
+        }
+        plogd("requestSatelliteAccessConfigurationForCurrentLocation");
+        ResultReceiver internalResultReceiver = new ResultReceiver(this) {
+            @Override
+            protected void onReceiveResult(int resultCode, Bundle resultData) {
+                plogd("requestSatelliteAccessConfigurationForCurrentLocation: resultCode="
+                        + resultCode + ", resultData=" + resultData);
+                boolean isSatelliteCommunicationAllowed = false;
+                if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                    if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
+                        isSatelliteCommunicationAllowed =
+                                resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
+                    } else {
+                        loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
+                        result.send(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
+                        return;
+                    }
+                } else {
+                    loge("resultCode is not SATELLITE_RESULT_SUCCESS.");
+                    result.send(resultCode, null);
+                    return;
+                }
+
+                SatelliteAccessConfiguration satelliteAccessConfig = null;
+                synchronized (mLock) {
+                    if (isSatelliteCommunicationAllowed && isRegionalConfigIdValid(
+                            mRegionalConfigId)) {
+                        plogd("requestSatelliteAccessConfigurationForCurrentLocation : "
+                                + "mRegionalConfigId is " + mRegionalConfigId);
+                        satelliteAccessConfig =
+                                mSatelliteAccessConfigMap.get(mRegionalConfigId);
+                    }
+                }
+                plogd("requestSatelliteAccessConfigurationForCurrentLocation : "
+                        + "satelliteAccessConfig is " + satelliteAccessConfig);
+                Bundle bundle = new Bundle();
+                bundle.putParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION, satelliteAccessConfig);
+                result.send(resultCode, bundle);
+            }
+        };
+        requestIsCommunicationAllowedForCurrentLocation(internalResultReceiver, false);
+    }
+
+    private boolean isRegionalConfigIdValid(@Nullable Integer configId) {
+        return (configId != null && configId >= 0);
     }
 
     /**
@@ -1125,8 +1217,8 @@
                         if (isRegionDisallowed(networkCountryIsoList)) {
                             Bundle bundle = new Bundle();
                             bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
-                            mAccessControllerMetricsStats.setAccessControlType(
-                                    SatelliteConstants.ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE)
+                            mAccessControllerMetricsStats.setAccessControlType(SatelliteConstants
+                                            .ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE)
                                     .setCountryCodes(networkCountryIsoList);
                             sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
                                     false);
@@ -1180,6 +1272,8 @@
         synchronized (mLock) {
             for (ResultReceiver resultReceiver : mSatelliteAllowResultReceivers) {
                 resultReceiver.send(resultCode, resultData);
+                mSatelliteController.decrementResultReceiverCount(
+                        "SAC:requestIsCommunicationAllowedForCurrentLocation");
             }
             mSatelliteAllowResultReceivers.clear();
         }
@@ -1704,8 +1798,11 @@
                                 location.getLatitude(),
                                 location.getLongitude(), mS2Level);
                 boolean satelliteAllowed;
+
                 if (mCachedAccessRestrictionMap.containsKey(locationToken)) {
-                    satelliteAllowed = mCachedAccessRestrictionMap.get(locationToken);
+                    mNewRegionalConfigId = mCachedAccessRestrictionMap.get(locationToken);
+                    satelliteAllowed = (mNewRegionalConfigId != null);
+                    plogd("mNewRegionalConfigId is " + mNewRegionalConfigId);
                 } else {
                     if (!initSatelliteOnDeviceAccessController()) {
                         ploge("Failed to init SatelliteOnDeviceAccessController");
@@ -1718,16 +1815,20 @@
 
                     if (mFeatureFlags.carrierRoamingNbIotNtn()) {
                         synchronized (mLock) {
-                            mRegionalConfigId = mSatelliteOnDeviceAccessController
+                            mNewRegionalConfigId = mSatelliteOnDeviceAccessController
                                     .getRegionalConfigIdForLocation(locationToken);
-                            plogd("mRegionalConfigId is " + mRegionalConfigId);
-                            satelliteAllowed = (mRegionalConfigId != null);
+                            plogd("mNewRegionalConfigId is " + mNewRegionalConfigId);
+                            satelliteAllowed = (mNewRegionalConfigId != null);
                         }
                     } else {
+                        plogd("checkSatelliteAccessRestrictionForLocation: "
+                                + "carrierRoamingNbIotNtn is disabled");
                         satelliteAllowed = mSatelliteOnDeviceAccessController
                                 .isSatCommunicationAllowedAtLocation(locationToken);
+                        mNewRegionalConfigId =
+                                satelliteAllowed ? UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID : null;
                     }
-                    updateCachedAccessRestrictionMap(locationToken, satelliteAllowed);
+                    updateCachedAccessRestrictionMap(locationToken, mNewRegionalConfigId);
                 }
                 mAccessControllerMetricsStats.setOnDeviceLookupTime(mOnDeviceLookupStartTimeMillis);
                 Bundle bundle = new Bundle();
@@ -1756,11 +1857,23 @@
         }
     }
 
+    private void updateRegionalConfigId() {
+        synchronized (mLock) {
+            plogd("mNewRegionalConfigId: updatedValue = " + mNewRegionalConfigId
+                    + " | mRegionalConfigId: beforeValue = " + mRegionalConfigId);
+            if (!Objects.equals(mRegionalConfigId, mNewRegionalConfigId)) {
+                mRegionalConfigId = mNewRegionalConfigId;
+                notifyRegionalSatelliteConfigurationChanged(
+                        mSatelliteAccessConfigMap.get(mRegionalConfigId));
+            }
+        }
+    }
+
     private void updateCachedAccessRestrictionMap(
             @NonNull SatelliteOnDeviceAccessController.LocationToken locationToken,
-            boolean satelliteAllowed) {
+            Integer regionalConfigId) {
         synchronized (mLock) {
-            mCachedAccessRestrictionMap.put(locationToken, satelliteAllowed);
+            mCachedAccessRestrictionMap.put(locationToken, regionalConfigId);
         }
     }
 
@@ -2199,6 +2312,14 @@
                     logd("registerForCommunicationAllowedStateChanged: "
                             + "mCurrentSatelliteAllowedState " + mCurrentSatelliteAllowedState);
                 }
+                synchronized (mLock) {
+                    SatelliteAccessConfiguration satelliteAccessConfig =
+                            mSatelliteAccessConfigMap.get(mRegionalConfigId);
+                    callback.onSatelliteAccessConfigurationChanged(satelliteAccessConfig);
+                    logd("registerForCommunicationAllowedStateChanged: satelliteAccessConfig: "
+                            + satelliteAccessConfig + " of mRegionalConfigId: "
+                            + mRegionalConfigId);
+                }
             } catch (RemoteException ex) {
                 ploge("registerForCommunicationAllowedStateChanged: RemoteException ex=" + ex);
             }
@@ -2382,6 +2503,25 @@
         });
     }
 
+    protected void notifyRegionalSatelliteConfigurationChanged(
+            @Nullable SatelliteAccessConfiguration satelliteAccessConfig) {
+        plogd("notifyRegionalSatelliteConfigurationChanged : satelliteAccessConfig is "
+                + satelliteAccessConfig);
+
+        List<ISatelliteCommunicationAllowedStateCallback> deadCallersList = new ArrayList<>();
+        mSatelliteCommunicationAllowedStateChangedListeners.values().forEach(listener -> {
+            try {
+                listener.onSatelliteAccessConfigurationChanged(satelliteAccessConfig);
+            } catch (RemoteException e) {
+                plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e);
+                deadCallersList.add(listener);
+            }
+        });
+        deadCallersList.forEach(listener -> {
+            mSatelliteCommunicationAllowedStateChangedListeners.remove(listener.asBinder());
+        });
+    }
+
     private void reportMetrics(int resultCode, boolean allowed) {
         if (resultCode == SATELLITE_RESULT_SUCCESS) {
             mControllerMetricsStats.reportAllowedSatelliteAccessCount(allowed);
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index abc7289..4d98d92 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();
@@ -2143,26 +2154,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);
 
@@ -2170,16 +2191,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/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 7f0c800..af1ddb6 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -430,9 +430,9 @@
 
         super(phoneAccountHandle);
 
-        mTelecomAccountRegistry = telecomAccountRegistry;
-        mFeatureFlagProxy = featureFlagProxy;
-        mCarrierConfig = carrierConfig;
+        mTelecomAccountRegistry = Objects.requireNonNull(telecomAccountRegistry);
+        mFeatureFlagProxy = Objects.requireNonNull(featureFlagProxy);
+        mCarrierConfig = Objects.requireNonNull(carrierConfig);
 
         // Specify the connection time of the conference to be the connection time of the original
         // connection.
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index fa2151b..ca3bcfe 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -142,9 +142,9 @@
     public ImsConferenceController(TelecomAccountRegistry telecomAccountRegistry,
             TelephonyConnectionServiceProxy connectionService,
             ImsConference.FeatureFlagProxy featureFlagProxy) {
-        mConnectionService = connectionService;
-        mTelecomAccountRegistry = telecomAccountRegistry;
-        mFeatureFlagProxy = featureFlagProxy;
+        mConnectionService = Objects.requireNonNull(connectionService);
+        mTelecomAccountRegistry = Objects.requireNonNull(telecomAccountRegistry);
+        mFeatureFlagProxy = Objects.requireNonNull(featureFlagProxy);
     }
 
     void addConference(ImsConference conference) {
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index c7d97f5..8956266 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -70,6 +70,7 @@
 import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.phone.PhoneGlobals;
+import com.android.phone.PhoneInterfaceManager;
 import com.android.phone.PhoneUtils;
 import com.android.phone.R;
 import com.android.telephony.Rlog;
@@ -651,8 +652,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 +698,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 +710,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 +723,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 +735,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 +747,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 +759,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 +773,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 +787,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 +800,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 +815,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 +828,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 +838,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 +851,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);
@@ -1054,8 +1063,10 @@
 
             boolean hasVoiceAvailability = isImsVoiceAvailable();
 
-            boolean isRttSupported = PhoneGlobals.getInstance().phoneMgr
-                    .isRttEnabled(mPhone.getSubId());
+            PhoneInterfaceManager phoneMgr = PhoneGlobals.getInstance()
+                .phoneMgr;
+            boolean isRttSupported = (phoneMgr != null) ?
+                phoneMgr.isRttEnabled(mPhone.getSubId()) : false;
 
             boolean isRoaming = mTelephonyManager.isNetworkRoaming(mPhone.getSubId());
             boolean isOnWfc = mPhone.getImsRegistrationTech()
diff --git a/testapps/TestSatelliteApp/AndroidManifest.xml b/testapps/TestSatelliteApp/AndroidManifest.xml
index eaddf95..a1f22fa 100644
--- a/testapps/TestSatelliteApp/AndroidManifest.xml
+++ b/testapps/TestSatelliteApp/AndroidManifest.xml
@@ -20,6 +20,7 @@
     <uses-permission android:name="android.permission.BIND_SATELLITE_SERVICE"/>
     <uses-permission android:name="android.permission.SATELLITE_COMMUNICATION"/>
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.SEND_SMS"/>
     <application android:label="SatelliteTestApp">
         <activity android:name=".SatelliteTestApp"
              android:label="SatelliteTestApp"
diff --git a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
index 9aec52b..d046f03 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
@@ -191,6 +191,19 @@
             android:layout_height="wrap_content"
             android:paddingRight="4dp"
             android:text="@string/deprovisionSatellite"/>
+        <Button
+            android:id="@+id/setNtnSmsSupportedTrue"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/setNtnSmsSupportedTrue"/>
+        <Button
+            android:id="@+id/setNtnSmsSupportedFalse"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/setNtnSmsSupportedFalse"/>
+
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
index 54f2722..4b5ea5b 100644
--- a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -97,6 +97,9 @@
     <string name="requestSatelliteSubscriberProvisionStatus">requestSatelliteSubscriberProvisionStatus</string>
     <string name="provisionSatellite">provisionSatellite</string>
     <string name="deprovisionSatellite">deprovisionSatellite</string>
+    <string name="setNtnSmsSupportedTrue">setNtnSmsSupportedTrue</string>
+    <string name="setNtnSmsSupportedFalse">setNtnSmsSupportedFalse</string>
+
 
     <string name="Back">Back</string>
     <string name="ClearLog">Clear Log</string>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
index 7c4ae00..cb56e87 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteTestApp.java
@@ -16,11 +16,13 @@
 
 package com.android.phone.testapps.satellitetestapp;
 
+import android.Manifest;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.telephony.satellite.stub.SatelliteDatagram;
@@ -42,6 +44,7 @@
 
     private TestSatelliteServiceConnection mSatelliteServiceConn;
     private List<SatelliteDatagram> mSentSatelliteDatagrams = new ArrayList<>();
+    private static final int REQUEST_CODE_SEND_SMS = 1;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -105,6 +108,16 @@
         });
     }
 
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (checkSelfPermission(Manifest.permission.SEND_SMS)
+                != PackageManager.PERMISSION_GRANTED) {
+            requestPermissions(new String[]{Manifest.permission.SEND_SMS}, REQUEST_CODE_SEND_SMS);
+        }
+    }
+
+
     private final ILocalSatelliteListener mSatelliteListener =
             new ILocalSatelliteListener.Stub() {
                 @Override
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index 97cb9c3..7d5e9af 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -127,6 +127,11 @@
                 .setOnClickListener(this::provisionSatellite);
         findViewById(R.id.deprovisionSatelliteWrapper)
                 .setOnClickListener(this::deprovisionSatellite);
+        findViewById(R.id.setNtnSmsSupportedTrue)
+                .setOnClickListener(this::setNtnSmsSupportedTrue);
+        findViewById(R.id.setNtnSmsSupportedFalse)
+                .setOnClickListener(this::setNtnSmsSupportedFalse);
+
 
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
@@ -799,6 +804,31 @@
         }
     }
 
+    private void setNtnSmsSupportedTrue(View view) {
+        setNtnSmsSupported(true);
+    }
+
+    private void setNtnSmsSupportedFalse(View view) {
+        setNtnSmsSupported(false);
+    }
+
+    private void setNtnSmsSupported(boolean ntnSmsSupported) {
+        String msg = "setNtnSmsSupported:" + ntnSmsSupported;
+        addLogMessage(msg);
+        logd(msg);
+
+        try {
+            mSatelliteManagerWrapper.setNtnSmsSupported(ntnSmsSupported);
+            msg = "setNtnSmsSupported=" + ntnSmsSupported + " is successful";
+            logd(msg);
+            addLogMessage(msg);
+        } catch (SecurityException | IllegalStateException ex) {
+            msg = "setNtnSmsSupported=" + ntnSmsSupported + " failed. " + ex.getMessage();
+            logd(msg);
+            addLogMessage(msg);
+        }
+    }
+
     private int getActiveSubId() {
         int subId;
         List<SubscriptionInfo> subscriptionInfoList =
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 2bc7bb9..3e74eb7 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -16,21 +16,38 @@
 
 package com.android;
 
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
 
+import android.content.ContextWrapper;
+import android.content.res.Resources;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Log;
 
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.telephony.GsmCdmaPhone;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.data.DataConfigManager;
+import com.android.internal.telephony.data.DataNetworkController;
+import com.android.phone.PhoneGlobals;
+import com.android.phone.PhoneInterfaceManager;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
+import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
 import java.lang.reflect.Field;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -39,12 +56,15 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * Helper class to load Mockito Resources into a test.
+ * Helper class to load Mockito Resources into Telephony unit tests.
  */
 public class TelephonyTestBase {
     @Rule public final MockitoRule mocks = MockitoJUnit.rule();
 
     protected TestContext mContext;
+    @Mock protected PhoneGlobals mPhoneGlobals;
+    @Mock protected GsmCdmaPhone mPhone;
+    @Mock protected DataNetworkController mDataNetworkController;
 
     private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
     private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
@@ -55,7 +75,31 @@
             Looper.prepare();
         }
 
+        doCallRealMethod().when(mPhoneGlobals).getBaseContext();
+        doCallRealMethod().when(mPhoneGlobals).getResources();
+        doCallRealMethod().when(mPhone).getServiceState();
+
         mContext = spy(new TestContext());
+        doReturn(mContext).when(mPhone).getContext();
+        replaceInstance(ContextWrapper.class, "mBase", mPhoneGlobals, mContext);
+
+        Resources resources = InstrumentationRegistry.getTargetContext().getResources();
+        assertNotNull(resources);
+        doReturn(resources).when(mContext).getResources();
+
+        replaceInstance(Handler.class, "mLooper", mPhone, Looper.myLooper());
+        replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true);
+        replaceInstance(PhoneFactory.class, "sPhone", null, mPhone);
+        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
+        replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
+
+        doReturn(mDataNetworkController).when(mPhone).getDataNetworkController();
+        doReturn(Collections.emptyList()).when(mDataNetworkController)
+                .getInternetDataDisallowedReasons();
+        doReturn(Mockito.mock(DataConfigManager.class)).when(mDataNetworkController)
+                .getDataConfigManager();
+
+        mPhoneGlobals.phoneMgr = Mockito.mock(PhoneInterfaceManager.class);
     }
 
     @After
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index e464ad5..a684ef5 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -103,6 +103,11 @@
     }
 
     @Override
+    public String getOpPackageName() {
+        return getPackageName();
+    }
+
+    @Override
     public String getAttributionTag() {
         return "";
     }
@@ -212,6 +217,11 @@
     }
 
     @Override
+    public Looper getMainLooper() {
+        return Looper.getMainLooper();
+    }
+
+    @Override
     public Handler getMainThreadHandler() {
         return new Handler(Looper.getMainLooper());
     }
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index 99064dd..5190b21 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -41,7 +41,6 @@
 import android.content.res.Resources;
 import android.os.Build;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.PermissionEnforcer;
 import android.os.PersistableBundle;
 import android.os.UserHandle;
@@ -51,16 +50,13 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyRegistryManager;
+import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
-import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.IccCardConstants;
-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.SubscriptionManagerService;
 
@@ -75,7 +71,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -84,7 +79,8 @@
 /**
  * Unit Test for CarrierConfigLoader.
  */
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class CarrierConfigLoaderTest extends TelephonyTestBase {
     @Rule
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
@@ -107,12 +103,10 @@
     @Mock SharedPreferences mSharedPreferences;
     @Mock TelephonyRegistryManager mTelephonyRegistryManager;
     @Mock FeatureFlags mFeatureFlags;
-    @Mock GsmCdmaPhone mMockPhone;
 
     private TelephonyManager mTelephonyManager;
     private CarrierConfigLoader mCarrierConfigLoader;
     private Handler mHandler;
-    private HandlerThread mHandlerThread;
     private TestableLooper mTestableLooper;
 
     // The AIDL stub will use PermissionEnforcer to check permission from the caller.
@@ -121,10 +115,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        MockitoAnnotations.initMocks(this);
-        Phone[] mPhones = new Phone[]{mMockPhone};
-        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
-        replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true);
         doReturn(Context.PERMISSION_ENFORCER_SERVICE).when(mContext).getSystemServiceName(
                 eq(PermissionEnforcer.class));
         doReturn(mFakePermissionEnforcer).when(mContext).getSystemService(
@@ -158,10 +148,7 @@
         when(mContext.getSystemService(TelephonyRegistryManager.class)).thenReturn(
                 mTelephonyRegistryManager);
 
-        mHandlerThread = new HandlerThread("CarrierConfigLoaderTest");
-        mHandlerThread.start();
-
-        mTestableLooper = new TestableLooper(mHandlerThread.getLooper());
+        mTestableLooper = TestableLooper.get(this);
         mCarrierConfigLoader = new CarrierConfigLoader(mContext, mTestableLooper.getLooper(),
                 mFeatureFlags);
         mHandler = mCarrierConfigLoader.getHandler();
@@ -176,8 +163,6 @@
         mFakePermissionEnforcer.revoke(android.Manifest.permission.DUMP);
         mFakePermissionEnforcer.revoke(android.Manifest.permission.MODIFY_PHONE_STATE);
         mFakePermissionEnforcer.revoke(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
-        mTestableLooper.destroy();
-        mHandlerThread.quit();
         super.tearDown();
     }
 
diff --git a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
index 0e902a8..5521ac0 100644
--- a/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
+++ b/tests/src/com/android/phone/ImsStateCallbackControllerTest.java
@@ -46,7 +46,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.Looper;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyRegistryManager;
 import android.testing.TestableLooper;
@@ -70,7 +69,6 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -110,7 +108,6 @@
     @Captor ArgumentCaptor<FeatureConnector.Listener<ImsManager>> mMmTelConnectorListenerSlot1;
     @Captor ArgumentCaptor<FeatureConnector.Listener<RcsFeatureManager>> mRcsConnectorListenerSlot0;
     @Captor ArgumentCaptor<FeatureConnector.Listener<RcsFeatureManager>> mRcsConnectorListenerSlot1;
-    @Mock private PhoneGlobals mPhone;
     @Mock ImsStateCallbackController.PhoneFactoryProxy mPhoneFactoryProxy;
     @Mock Phone mPhoneSlot0;
     @Mock Phone mPhoneSlot1;
@@ -134,16 +131,16 @@
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        super.setUp();
 
-        when(mPhone.getMainExecutor()).thenReturn(mExecutor);
-        when(mPhone.getSystemServiceName(eq(SubscriptionManager.class)))
+        when(mPhoneGlobals.getMainExecutor()).thenReturn(mExecutor);
+        when(mPhoneGlobals.getSystemServiceName(eq(SubscriptionManager.class)))
                 .thenReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        when(mPhone.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
+        when(mPhoneGlobals.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
                 .thenReturn(mSubscriptionManager);
-        when(mPhone.getSystemServiceName(eq(TelephonyRegistryManager.class)))
+        when(mPhoneGlobals.getSystemServiceName(eq(TelephonyRegistryManager.class)))
                 .thenReturn(Context.TELEPHONY_REGISTRY_SERVICE);
-        when(mPhone.getSystemService(eq(Context.TELEPHONY_REGISTRY_SERVICE)))
+        when(mPhoneGlobals.getSystemService(eq(Context.TELEPHONY_REGISTRY_SERVICE)))
                 .thenReturn(mTelephonyRegistryManager);
         when(mPhoneFactoryProxy.getPhone(eq(0))).thenReturn(mPhoneSlot0);
         when(mPhoneFactoryProxy.getPhone(eq(1))).thenReturn(mPhoneSlot1);
@@ -937,9 +934,6 @@
     }
 
     private void createController(int slotCount) throws Exception {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
         makeFakeActiveSubIds(slotCount);
 
         when(mMmTelFeatureFactory
@@ -956,7 +950,7 @@
                 .thenReturn(mRcsFeatureConnectorSlot1);
 
         mImsStateCallbackController =
-                new ImsStateCallbackController(mPhone, mHandlerThread.getLooper(),
+                new ImsStateCallbackController(mPhoneGlobals, mHandlerThread.getLooper(),
                         slotCount, mMmTelFeatureFactory, mRcsFeatureFactory, mImsResolver,
                         mFeatureFlags);
 
diff --git a/tests/src/com/android/phone/NotificationMgrTest.java b/tests/src/com/android/phone/NotificationMgrTest.java
index 2b0ff94..0c1f8a3 100644
--- a/tests/src/com/android/phone/NotificationMgrTest.java
+++ b/tests/src/com/android/phone/NotificationMgrTest.java
@@ -77,11 +77,8 @@
 import com.android.TelephonyTestBase;
 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.SignalStrengthController;
-import com.android.internal.telephony.data.DataConfigManager;
-import com.android.internal.telephony.data.DataNetworkController;
 import com.android.internal.telephony.data.DataSettingsManager;
 import com.android.internal.telephony.util.NotificationChannelController;
 
@@ -90,9 +87,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
-import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -111,13 +106,12 @@
     private static final String MOBILE_NETWORK_SELECTION_CLASS = ".testClass";
     private static final String CARRIER_NAME = "CoolCarrier";
 
-    @Mock PhoneGlobals mApp;
+    PhoneGlobals mApp; // mPhoneGlobals alias
     @Mock StatusBarManager mStatusBarManager;
     @Mock UserManager mUserManager;
     @Mock SubscriptionManager mSubscriptionManager;
     @Mock TelecomManager mTelecomManager;
     @Mock TelephonyManager mTelephonyManager;
-    @Mock Phone mPhone;
     @Mock SharedPreferences mSharedPreferences;
     @Mock NotificationManager mNotificationManager;
     @Mock SubscriptionInfo mSubscriptionInfo;
@@ -126,20 +120,16 @@
     @Mock ServiceStateTracker mServiceStateTracker;
     @Mock ServiceState mServiceState;
     @Mock CarrierConfigManager mCarrierConfigManager;
-    @Mock DataNetworkController mDataNetworkController;
     @Mock DataSettingsManager mDataSettingsManager;
-    @Mock DataConfigManager mDataConfigManager;
     @Mock SignalStrengthController mSignalStrengthController;
 
-    private Phone[] mPhones;
     private NotificationMgr mNotificationMgr;
     private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mPhones = new Phone[]{mPhone};
-        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+        super.setUp();
+        mApp = mPhoneGlobals;
         when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
         when(mPhone.getContext()).thenReturn(mMockedContext);
         when(mMockedContext.getResources()).thenReturn(mResources);
@@ -152,10 +142,6 @@
         when(mPhone.getServiceStateTracker()).thenReturn(mServiceStateTracker);
         mServiceStateTracker.mSS = mServiceState;
         when(mPhone.getSignalStrengthController()).thenReturn(mSignalStrengthController);
-        when(mPhone.getDataNetworkController()).thenReturn(mDataNetworkController);
-        when(mDataNetworkController.getInternetDataDisallowedReasons()).thenReturn(
-                Collections.emptyList());
-        when(mDataNetworkController.getDataConfigManager()).thenReturn(mDataConfigManager);
         when(mPhone.getDataSettingsManager()).thenReturn(mDataSettingsManager);
         when(mDataSettingsManager.isDataEnabledForReason(anyInt())).thenReturn(true);
         when(mApp.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences);
diff --git a/tests/src/com/android/phone/PhoneInterfaceManagerTest.java b/tests/src/com/android/phone/PhoneInterfaceManagerTest.java
index 5ecf111..ef6a02a 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();
@@ -90,8 +92,6 @@
             PhoneInterfaceManagerTest.class.getPackageName();
 
     @Mock
-    PhoneGlobals mPhoneGlobals;
-    @Mock
     Phone mPhone;
     @Mock
     FeatureFlags mFeatureFlags;
@@ -121,6 +121,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 +505,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/PhoneUtilsTest.java b/tests/src/com/android/phone/PhoneUtilsTest.java
index 3d7815c..2d3d065 100644
--- a/tests/src/com/android/phone/PhoneUtilsTest.java
+++ b/tests/src/com/android/phone/PhoneUtilsTest.java
@@ -30,15 +30,11 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
-import com.android.internal.telephony.GsmCdmaPhone;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 public class PhoneUtilsTest extends TelephonyTestBase {
@@ -46,8 +42,6 @@
     private SubscriptionManager mMockSubscriptionManager;
     @Mock
     private SubscriptionInfo mMockSubscriptionInfo;
-    @Mock
-    private GsmCdmaPhone mMockPhone;
 
     private final int mPhoneAccountHandleIdInteger = 123;
     private final String mPhoneAccountHandleIdString = "123";
@@ -58,12 +52,10 @@
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        super.setUp();
         when(mMockSubscriptionManager.getActiveSubscriptionInfo(
                 eq(mPhoneAccountHandleIdInteger))).thenReturn(mMockSubscriptionInfo);
-        when(mMockPhone.getSubId()).thenReturn(mPhoneAccountHandleIdInteger);
-        Phone[] mPhones = new Phone[] {mMockPhone};
-        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+        when(mPhone.getSubId()).thenReturn(mPhoneAccountHandleIdInteger);
     }
 
     @Test
@@ -74,7 +66,7 @@
 
     @Test
     public void testGetPhoneForPhoneAccountHandle() throws Exception {
-        assertEquals(mMockPhone, PhoneUtils.getPhoneForPhoneAccountHandle(
+        assertEquals(mPhone, PhoneUtils.getPhoneForPhoneAccountHandle(
                 mPhoneAccountHandleTest));
     }
 
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
index 678d069..27f3ef7 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
@@ -16,20 +16,19 @@
 
 package com.android.phone.satellite.accesscontrol;
 
-import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
-
 import static org.junit.Assert.assertEquals;
 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.junit.Assert.fail;
 import static org.mockito.Mockito.doReturn;
 
+import android.annotation.Nullable;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.telephony.flags.FeatureFlags;
-import com.android.storage.s2.S2LevelRange;
-
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.utils.TestUtils;
@@ -73,18 +72,42 @@
 
     @Test
     public void testSatelliteAccessControl_AllowedList() throws Exception {
-        testSatelliteAccessControl(true);
+        testSatelliteAccessControl(true, null);
     }
 
     @Test
     public void testSatelliteAccessControl_DisallowedList() throws Exception {
-        testSatelliteAccessControl(false);
+        testSatelliteAccessControl(false, null);
     }
 
-    private void testSatelliteAccessControl(boolean isAllowedList) throws Exception {
+    @Test
+    public void testSatelliteAccessControl_AllowedList_validEntryValue() throws Exception {
+        testSatelliteAccessControl(true, 1);
+    }
+
+    @Test
+    public void testSatelliteAccessControl_DisallowedList_validEntryValue() {
+        assertThrows(IllegalArgumentException.class,
+                () -> testSatelliteAccessControl(false, 1));
+    }
+
+    private void testSatelliteAccessControl(boolean isAllowedList, @Nullable Integer entryValue)
+            throws Exception {
+        final int defaultEntryValue = -1;
+
+        if (!isAllowedList && entryValue != null) {
+            throw new IllegalArgumentException(
+                    "isAllowedList must be true when entryValue is present.");
+        }
+
+        List<Integer> expectedConfigIds = List.of(1, 1, 3);
         SatS2RangeFileFormat fileFormat = null;
         try {
-            fileFormat = createSatS2File(mFile, isAllowedList);
+            if (entryValue == null) {
+                fileFormat = createSatS2File(mFile, isAllowedList);
+            } else {
+                fileFormat = createSatS2FileWithEntryValue(mFile, isAllowedList, expectedConfigIds);
+            }
         } catch (Exception ex) {
             fail("Got unexpected exception in createSatS2File, ex=" + ex);
         }
@@ -94,6 +117,10 @@
         try {
             accessController = SatelliteOnDeviceAccessController.create(mFile, mMockFeatureFlags);
             int s2Level = accessController.getS2Level();
+            if (entryValue == null) {
+                expectedConfigIds = List.of(defaultEntryValue, defaultEntryValue,
+                        defaultEntryValue);
+            }
 
             // Verify an edge cell of range 1 not in the output file
             S2CellId s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1000, 999));
@@ -111,12 +138,7 @@
             assertTrue(isAllowed != isAllowedList);
 
             Integer configId = accessController.getRegionalConfigIdForLocation(locationToken);
-            if (isAllowedList) {
-                assertNull(configId);
-            } else {
-                assertNotNull(configId);
-                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-            }
+            assertNull(configId);
 
             // Verify cells in range1 present in the output file
             for (int suffix = 1000; suffix < 2000; suffix++) {
@@ -130,12 +152,8 @@
                 assertTrue(isAllowed == isAllowedList);
 
                 configId = accessController.getRegionalConfigIdForLocation(locationToken);
-                if (isAllowedList) {
-                    assertNotNull(configId);
-                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-                } else {
-                    assertNull(configId);
-                }
+                assertNotNull(configId);
+                assertEquals((int) expectedConfigIds.get(0), (int) configId);
             }
 
             // Verify the middle cell not in the output file
@@ -147,12 +165,8 @@
             assertTrue(isAllowed != isAllowedList);
 
             configId = accessController.getRegionalConfigIdForLocation(locationToken);
-            if (isAllowedList) {
-                assertNull(configId);
-            } else {
-                assertNotNull(configId);
-                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-            }
+            assertNull(configId);
+
 
             // Verify cells in range2 present in the output file
             for (int suffix = 2001; suffix < 3000; suffix++) {
@@ -164,12 +178,8 @@
                 assertTrue(isAllowed == isAllowedList);
 
                 configId = accessController.getRegionalConfigIdForLocation(locationToken);
-                if (isAllowedList) {
-                    assertNotNull(configId);
-                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-                } else {
-                    assertNull(configId);
-                }
+                assertNotNull(configId);
+                assertEquals((int) expectedConfigIds.get(1), (int) configId);
             }
 
             // Verify an edge cell of range 2 not in the output file
@@ -181,12 +191,7 @@
             assertTrue(isAllowed != isAllowedList);
 
             configId = accessController.getRegionalConfigIdForLocation(locationToken);
-            if (isAllowedList) {
-                assertNull(configId);
-            } else {
-                assertNotNull(configId);
-                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-            }
+            assertNull(configId);
 
             // Verify an edge cell of range 3 not in the output file
             s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1001, 999));
@@ -197,12 +202,7 @@
             assertTrue(isAllowed != isAllowedList);
 
             configId = accessController.getRegionalConfigIdForLocation(locationToken);
-            if (isAllowedList) {
-                assertNull(configId);
-            } else {
-                assertNotNull(configId);
-                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-            }
+            assertNull(configId);
 
             // Verify cells in range1 present in the output file
             for (int suffix = 1000; suffix < 2000; suffix++) {
@@ -214,12 +214,8 @@
                 assertTrue(isAllowed == isAllowedList);
 
                 configId = accessController.getRegionalConfigIdForLocation(locationToken);
-                if (isAllowedList) {
-                    assertNotNull(configId);
-                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-                } else {
-                    assertNull(configId);
-                }
+                assertNotNull(configId);
+                assertEquals((int) expectedConfigIds.get(2), (int) configId);
             }
 
             // Verify an edge cell of range 3 not in the output file
@@ -231,12 +227,7 @@
             assertTrue(isAllowed != isAllowedList);
 
             configId = accessController.getRegionalConfigIdForLocation(locationToken);
-            if (isAllowedList) {
-                assertNull(configId);
-            } else {
-                assertNotNull(configId);
-                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
-            }
+            assertNull(configId);
 
         } catch (Exception ex) {
             fail("Unexpected exception when validating the output ex=" + ex);
@@ -247,8 +238,8 @@
         }
     }
 
-    private SatS2RangeFileFormat createSatS2File(
-            File file, boolean isAllowedList) throws Exception {
+    private SatS2RangeFileFormat createSatS2File(File file, boolean isAllowedList)
+            throws Exception {
         SatS2RangeFileFormat fileFormat;
         SuffixTableRange range1, range2, range3;
         try (SatS2RangeFileWriter satS2RangeFileWriter = SatS2RangeFileWriter.open(
@@ -276,4 +267,38 @@
         assertTrue(file.length() > 0);
         return fileFormat;
     }
+
+    private SatS2RangeFileFormat createSatS2FileWithEntryValue(
+            File file, boolean isAllowedList, List<Integer> entryValues) throws Exception {
+
+        SatS2RangeFileFormat fileFormat;
+        SuffixTableRange range1, range2, range3;
+        try (SatS2RangeFileWriter satS2RangeFileWriter = SatS2RangeFileWriter.open(
+                file, TestUtils.createS2RangeFileFormat(isAllowedList, 4, 1))) {
+            fileFormat = satS2RangeFileWriter.getFileFormat();
+
+            // Two ranges that share a prefix.
+            range1 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 1000),
+                    TestUtils.createCellId(fileFormat, 1, 1000, 2000),
+                    entryValues.get(0));
+            range2 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 2001),
+                    TestUtils.createCellId(fileFormat, 1, 1000, 3000),
+                    entryValues.get(1));
+            // This range has a different prefix, so will be in a different suffix table.
+            range3 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1001, 1000),
+                    TestUtils.createCellId(fileFormat, 1, 1001, 2000),
+                    entryValues.get(2));
+
+            List<SuffixTableRange> ranges = new ArrayList<>();
+            ranges.add(range1);
+            ranges.add(range2);
+            ranges.add(range3);
+            satS2RangeFileWriter.createSortedSuffixBlocks(ranges.iterator());
+        }
+        assertTrue(file.length() > 0);
+        return fileFormat;
+    }
 }
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index c2f5979..5c18cc5 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -17,6 +17,8 @@
 package com.android.phone.satellite.accesscontrol;
 
 import static android.location.LocationManager.MODE_CHANGED_ACTION;
+import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ACCESS_CONFIGURATION;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED;
@@ -29,15 +31,17 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.ALLOWED_STATE_CACHE_VALID_DURATION_NANOS;
-import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
-import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_COUNTRY_CODE_CHANGED;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.CMD_IS_SATELLITE_COMMUNICATION_ALLOWED;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_DELAY_MINUTES_BEFORE_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_S2_LEVEL;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_THROTTLE_INTERVAL_FOR_LOCATION_QUERY_MINUTES;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_CONFIG_DATA_UPDATED;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_COUNTRY_CODE_CHANGED;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.GOOGLE_US_SAN_SAT_S2_FILE_NAME;
-import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -51,6 +55,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -83,13 +88,18 @@
 import android.os.DropBoxManager;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.telecom.TelecomManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
+import android.telephony.satellite.SatelliteAccessConfiguration;
+import android.telephony.satellite.SatelliteInfo;
 import android.telephony.satellite.SatelliteManager;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -124,6 +134,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -188,15 +199,16 @@
     @Mock
     private SharedPreferences.Editor mMockSharedPreferencesEditor;
     @Mock
-    private Map<SatelliteOnDeviceAccessController.LocationToken, Boolean>
+    private Map<SatelliteOnDeviceAccessController.LocationToken, Integer>
             mMockCachedAccessRestrictionMap;
     @Mock
+    HashMap<Integer, SatelliteAccessConfiguration> mMockSatelliteAccessConfigMap;
+
+    @Mock
     private Intent mMockLocationIntent;
     @Mock
     private Set<ResultReceiver> mMockSatelliteAllowResultReceivers;
     @Mock
-    private ResultReceiver mMockSatelliteSupportedResultReceiver;
-    @Mock
     private TelephonyManager mMockTelephonyManager;
     @Mock
     private PackageManager mMockPackageManager;
@@ -206,7 +218,11 @@
     private NotificationManager mMockNotificationManager;
     @Mock
     private ApplicationInfo mMockApplicationInfo;
-
+    @Mock
+    private ResultReceiver mMockResultReceiver;
+    @Mock
+    private ConcurrentHashMap<IBinder, ISatelliteCommunicationAllowedStateCallback>
+            mSatelliteCommunicationAllowedStateCallbackMap;
 
     private Looper mLooper;
     private TestableLooper mTestableLooper;
@@ -241,6 +257,8 @@
     private ArgumentCaptor<Integer> mResultCodeIntCaptor;
     @Captor
     private ArgumentCaptor<Bundle> mResultDataBundleCaptor;
+    @Captor
+    private ArgumentCaptor<ISatelliteCommunicationAllowedStateCallback> mAllowedStateCallbackCaptor;
 
     private boolean mQueriedSatelliteAllowed = false;
     private int mQueriedSatelliteAllowedResultCode = SATELLITE_RESULT_SUCCESS;
@@ -304,6 +322,7 @@
                 mMockCountryDetector);
         when(mMockSatelliteController.getSatellitePhone()).thenReturn(mMockPhone);
         when(mMockPhone.getSubId()).thenReturn(SubscriptionManager.getDefaultSubscriptionId());
+
         when(mMockContext.getResources()).thenReturn(mMockResources);
         when(mMockResources.getStringArray(
                 com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
@@ -430,11 +449,11 @@
         // and allowedState is false when the location is null and the cache is expired
         mSatelliteAccessControllerUT.elapsedRealtimeNanos =
                 ALLOWED_STATE_CACHE_VALID_DURATION_NANOS + 1;
-        Iterator<ResultReceiver> mockIterator = mock(Iterator.class);
-        doReturn(mockIterator).when(mMockSatelliteAllowResultReceivers).iterator();
-        doReturn(true, false).when(mockIterator).hasNext();
+        Iterator<ResultReceiver> mockResultReceiverIterator = mock(Iterator.class);
+        doReturn(mockResultReceiverIterator).when(mMockSatelliteAllowResultReceivers).iterator();
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
         doNothing().when(mMockSatelliteAllowResultReceivers).clear();
-        doReturn(mMockSatelliteSupportedResultReceiver).when(mockIterator).next();
+        doReturn(mMockResultReceiver).when(mockResultReceiverIterator).next();
         replaceInstance(SatelliteAccessController.class, "mSatelliteAllowResultReceivers",
                 mSatelliteAccessControllerUT, mMockSatelliteAllowResultReceivers);
         mSatelliteAccessControllerUT.setIsSatelliteCommunicationAllowedForCurrentLocationCache(
@@ -442,7 +461,7 @@
         mSatelliteAccessControllerUT.setLocationRequestCancellationSignalAsNull(false);
 
         sendCurrentLocationTimeoutEvent();
-        verify(mMockSatelliteSupportedResultReceiver)
+        verify(mMockResultReceiver)
                 .send(mResultCodeIntCaptor.capture(), any());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_LOCATION_NOT_AVAILABLE),
                 mResultCodeIntCaptor.getValue());
@@ -514,6 +533,314 @@
                 .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_US)));
     }
 
+
+    private void setSatelliteCommunicationAllowed() throws Exception {
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_oem_enabled_satellite_access_allow))
+                .thenReturn(TEST_SATELLITE_ALLOW);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockLocationManager).isLocationEnabled();
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
+        replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
+                mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
+        doReturn(true).when(mMockCachedAccessRestrictionMap).containsKey(any());
+        doReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID)
+                .when(mMockCachedAccessRestrictionMap).get(any());
+    }
+
+    @Test
+    public void testRequestSatelliteAccessConfigurationForCurrentLocation() throws Exception {
+        // setup result receiver and satellite access configuration data
+        ResultReceiver mockResultReceiver = mock(ResultReceiver.class);
+        ArgumentCaptor<Integer> resultCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+        ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        SatelliteAccessConfiguration satelliteAccessConfig = getSatelliteAccessConfiguration();
+
+        // setup satellite communication allwed state as true
+        setSatelliteCommunicationAllowed();
+
+        // setup map data of location and configId.
+        replaceInstance(SatelliteAccessController.class, "mSatelliteAccessConfigMap",
+                mSatelliteAccessControllerUT, mMockSatelliteAccessConfigMap);
+        doReturn(satelliteAccessConfig).when(mMockSatelliteAccessConfigMap).get(anyInt());
+        doReturn(null).when(mMockSatelliteAccessConfigMap).get(eq(null));
+        doReturn(null).when(mMockSatelliteAccessConfigMap)
+                .get(eq(UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID));
+
+        // setup callback
+        ISatelliteCommunicationAllowedStateCallback mockSatelliteAllowedStateCallback = mock(
+                ISatelliteCommunicationAllowedStateCallback.class);
+        ArgumentCaptor<SatelliteAccessConfiguration> satelliteAccessConfigurationCaptor =
+                ArgumentCaptor.forClass(SatelliteAccessConfiguration.class);
+
+        when(mSatelliteCommunicationAllowedStateCallbackMap.values())
+                .thenReturn(List.of(mockSatelliteAllowedStateCallback));
+        replaceInstance(SatelliteAccessController.class,
+                "mSatelliteCommunicationAllowedStateChangedListeners", mSatelliteAccessControllerUT,
+                mSatelliteCommunicationAllowedStateCallbackMap);
+
+        // Test when the featureFlags.carrierRoamingNbIotNtn() is false
+        doReturn(false).when(mMockFeatureFlags).carrierRoamingNbIotNtn();
+
+        clearInvocations(mockResultReceiver);
+        mSatelliteAccessControllerUT
+                .requestSatelliteAccessConfigurationForCurrentLocation(mockResultReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mockResultReceiver, times(1)).send(resultCodeCaptor.capture(),
+                bundleCaptor.capture());
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, (int) resultCodeCaptor.getValue());
+        assertNull(bundleCaptor.getValue());
+        verify(mockSatelliteAllowedStateCallback, never())
+                .onSatelliteAccessConfigurationChanged(any());
+
+        doReturn(true).when(mMockFeatureFlags).carrierRoamingNbIotNtn();
+
+        // satellite communication allowed state is enabled and
+        // regional config id is DEFAULT_REGIONAL_SATELLITE_CONFIG_ID.
+        clearInvocations(mockResultReceiver);
+        clearInvocations(mockSatelliteAllowedStateCallback);
+        mSatelliteAccessControllerUT
+                .requestSatelliteAccessConfigurationForCurrentLocation(mockResultReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mockResultReceiver, times(1)).send(resultCodeCaptor.capture(),
+                bundleCaptor.capture());
+        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, (int) resultCodeCaptor.getValue());
+        assertTrue(bundleCaptor.getValue().containsKey(KEY_SATELLITE_ACCESS_CONFIGURATION));
+        assertSame(bundleCaptor.getValue().getParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION,
+                SatelliteAccessConfiguration.class), satelliteAccessConfig);
+        verify(mockSatelliteAllowedStateCallback, times(1))
+                .onSatelliteAccessConfigurationChanged(
+                        satelliteAccessConfigurationCaptor.capture());
+        assertEquals(satelliteAccessConfigurationCaptor.getValue(), satelliteAccessConfig);
+
+        // satellite communication allowed state is disabled and
+        // regional config id is null.
+        clearInvocations(mockResultReceiver);
+        clearInvocations(mockSatelliteAllowedStateCallback);
+        when(mMockCachedAccessRestrictionMap.get(any())).thenReturn(null);
+        mSatelliteAccessControllerUT
+                .requestSatelliteAccessConfigurationForCurrentLocation(mockResultReceiver);
+        mTestableLooper.processAllMessages();
+
+        verify(mockResultReceiver, times(1)).send(resultCodeCaptor.capture(),
+                bundleCaptor.capture());
+        assertEquals(SATELLITE_RESULT_SUCCESS, (int) resultCodeCaptor.getValue());
+        assertTrue(bundleCaptor.getValue().containsKey(KEY_SATELLITE_ACCESS_CONFIGURATION));
+        assertNull(bundleCaptor.getValue().getParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION,
+                SatelliteAccessConfiguration.class));
+        verify(mockSatelliteAllowedStateCallback, times(1))
+                .onSatelliteAccessConfigurationChanged(
+                        satelliteAccessConfigurationCaptor.capture());
+        assertNull(satelliteAccessConfigurationCaptor.getValue());
+    }
+
+    private SatelliteAccessConfiguration getSatelliteAccessConfiguration() {
+        Parcel satelliteAccessconfigParcel = Parcel.obtain();
+
+        List<SatelliteInfo> satelliteInfoList = new ArrayList<>();
+        satelliteInfoList.add(mock(SatelliteInfo.class));
+        satelliteAccessconfigParcel.writeTypedList(satelliteInfoList);
+
+        List<Integer> tagIds = new ArrayList<>(List.of(1, 2));
+        satelliteAccessconfigParcel.writeList(tagIds);
+
+        return new SatelliteAccessConfiguration(satelliteAccessconfigParcel);
+    }
+
+    @Test
+    public void testRegisterForCommunicationAllowedStateChanged() throws Exception {
+        ISatelliteCommunicationAllowedStateCallback mockSatelliteAllowedStateCallback = mock(
+                ISatelliteCommunicationAllowedStateCallback.class);
+        doReturn(true).when(mSatelliteCommunicationAllowedStateCallbackMap)
+                .put(any(IBinder.class), any(ISatelliteCommunicationAllowedStateCallback.class));
+        replaceInstance(SatelliteAccessController.class,
+                "mSatelliteCommunicationAllowedStateChangedListeners", mSatelliteAccessControllerUT,
+                mSatelliteCommunicationAllowedStateCallbackMap);
+
+        doReturn(false).when(mMockFeatureFlags).oemEnabledSatelliteFlag();
+        int result = mSatelliteAccessControllerUT.registerForCommunicationAllowedStateChanged(
+                DEFAULT_SUBSCRIPTION_ID, mockSatelliteAllowedStateCallback);
+        mTestableLooper.processAllMessages();
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, result);
+        verify(mockSatelliteAllowedStateCallback, never())
+                .onSatelliteCommunicationAllowedStateChanged(anyBoolean());
+        verify(mockSatelliteAllowedStateCallback, never())
+                .onSatelliteAccessConfigurationChanged(any(SatelliteAccessConfiguration.class));
+
+        doReturn(true).when(mMockFeatureFlags).oemEnabledSatelliteFlag();
+        result = mSatelliteAccessControllerUT.registerForCommunicationAllowedStateChanged(
+                DEFAULT_SUBSCRIPTION_ID, mockSatelliteAllowedStateCallback);
+        mTestableLooper.processAllMessages();
+        assertEquals(SATELLITE_RESULT_SUCCESS, result);
+        verify(mockSatelliteAllowedStateCallback, times(1))
+                .onSatelliteCommunicationAllowedStateChanged(anyBoolean());
+        verify(mockSatelliteAllowedStateCallback, times(1))
+                .onSatelliteAccessConfigurationChanged(
+                        nullable(SatelliteAccessConfiguration.class));
+    }
+
+    @Test
+    public void testNotifyRegionalSatelliteConfigurationChanged() throws Exception {
+        // setup test
+        ISatelliteCommunicationAllowedStateCallback mockSatelliteAllowedStateCallback = mock(
+                ISatelliteCommunicationAllowedStateCallback.class);
+        ArgumentCaptor<SatelliteAccessConfiguration> satelliteAccessConfigurationCaptor =
+                ArgumentCaptor.forClass(SatelliteAccessConfiguration.class);
+
+        when(mSatelliteCommunicationAllowedStateCallbackMap.values())
+                .thenReturn(List.of(mockSatelliteAllowedStateCallback));
+        replaceInstance(SatelliteAccessController.class,
+                "mSatelliteCommunicationAllowedStateChangedListeners", mSatelliteAccessControllerUT,
+                mSatelliteCommunicationAllowedStateCallbackMap);
+
+        // register callback
+        mSatelliteAccessControllerUT.registerForCommunicationAllowedStateChanged(
+                DEFAULT_SUBSCRIPTION_ID, mockSatelliteAllowedStateCallback);
+
+        // verify if the callback is
+        // the same instance from onmSatelliteCommunicationAllowedStateCallbackMap
+        verify(mSatelliteCommunicationAllowedStateCallbackMap).put(any(),
+                mAllowedStateCallbackCaptor.capture());
+        assertSame(mockSatelliteAllowedStateCallback, mAllowedStateCallbackCaptor.getValue());
+
+        // create SatelliteAccessConfiguration data for this test
+        SatelliteAccessConfiguration satelliteAccessConfig = getSatelliteAccessConfiguration();
+
+        // trigger notifyRegionalSatelliteConfigurationChanged
+        mSatelliteAccessControllerUT
+                .notifyRegionalSatelliteConfigurationChanged(satelliteAccessConfig);
+
+        // verify if the satelliteAccessConfig is the same instance with the captured one.
+        verify(mockSatelliteAllowedStateCallback).onSatelliteAccessConfigurationChanged(
+                satelliteAccessConfigurationCaptor.capture());
+        assertSame(satelliteAccessConfig, satelliteAccessConfigurationCaptor.getValue());
+    }
+
+    @Test
+    public void testCheckSatelliteAccessRestrictionForLocation() throws Exception {
+        // Setup
+        logd("testCheckSatelliteAccessRestrictionForLocation : setup");
+        ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        ArgumentCaptor<Integer> regionalConfigIdCaptor = ArgumentCaptor.forClass(Integer.class);
+        replaceInstance(SatelliteAccessController.class, "mS2Level",
+                mSatelliteAccessControllerUT, DEFAULT_S2_LEVEL);
+        Iterator<ResultReceiver> mockResultReceiverIterator = mock(Iterator.class);
+        mSatelliteAccessControllerUT.setRegionalConfigId(null);
+
+        doReturn(mockResultReceiverIterator).when(mMockSatelliteAllowResultReceivers).iterator();
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        doNothing().when(mMockSatelliteAllowResultReceivers).clear();
+        doReturn(mMockResultReceiver).when(mockResultReceiverIterator).next();
+        replaceInstance(SatelliteAccessController.class, "mSatelliteAllowResultReceivers",
+                mSatelliteAccessControllerUT, mMockSatelliteAllowResultReceivers);
+        replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
+                mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
+
+        // when mMockCachedAccessRestrictionMap is hit and has DEFAULT_REGIONAL_SATELLITE_CONFIG_ID,
+        // verify belows
+        // - the bundle data of KEY_SATELLITE_COMMUNICATION_ALLOWED is true
+        // - the newRegionalConfigId is the same as DEFAULT_REGIONAL_SATELLITE_CONFIG_ID
+        // - the regionalConfigId is the same as DEFAULT_REGIONAL_SATELLITE_CONFIG_ID
+        logd("testCheckSatelliteAccessRestrictionForLocation : case 1");
+        clearInvocations(mMockSatelliteOnDeviceAccessController);
+        clearInvocations(mMockCachedAccessRestrictionMap);
+
+        doReturn(true).when(mMockCachedAccessRestrictionMap)
+                .containsKey(any(SatelliteOnDeviceAccessController.LocationToken.class));
+        doReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID).when(mMockCachedAccessRestrictionMap)
+                .get(any(SatelliteOnDeviceAccessController.LocationToken.class));
+
+        mSatelliteAccessControllerUT.checkSatelliteAccessRestrictionForLocation(mMockLocation0);
+        verify(mMockResultReceiver, times(1))
+                .send(mResultCodeIntCaptor.capture(), bundleCaptor.capture());
+        verify(mMockSatelliteOnDeviceAccessController, never()).getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class));
+        assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS), mResultCodeIntCaptor.getValue());
+        assertTrue(bundleCaptor.getValue().getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED));
+        assertEquals(Integer.valueOf(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID),
+                mSatelliteAccessControllerUT.getNewRegionalConfigId());
+        assertEquals(Integer.valueOf(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID),
+                mSatelliteAccessControllerUT.getRegionalConfigId());
+
+        // when mMockCachedAccessRestrictionMap is not hit and regionalConfigId is null
+        // verify belows
+        // - the bundle data of KEY_SATELLITE_COMMUNICATION_ALLOWED is false
+        // - the regionalConfigId is null
+        logd("testCheckSatelliteAccessRestrictionForLocation : case 2");
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        doReturn(false).when(mMockCachedAccessRestrictionMap)
+                .containsKey(any(SatelliteOnDeviceAccessController.LocationToken.class));
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(null);
+
+        mSatelliteAccessControllerUT.checkSatelliteAccessRestrictionForLocation(mMockLocation0);
+        verify(mMockResultReceiver, times(2))
+                .send(mResultCodeIntCaptor.capture(), bundleCaptor.capture());
+        assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS), mResultCodeIntCaptor.getValue());
+        assertFalse(bundleCaptor.getValue().getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED));
+        verify(mMockCachedAccessRestrictionMap, times(1))
+                .put(any(), regionalConfigIdCaptor.capture());
+        assertNull(regionalConfigIdCaptor.getValue());
+        assertNull(mSatelliteAccessControllerUT.getNewRegionalConfigId());
+        assertNull(mSatelliteAccessControllerUT.getRegionalConfigId());
+
+        // when mMockCachedAccessRestrictionMap is not hit and
+        // regionalConfigId is DEFAULT_REGIONAL_SATELLITE_CONFIG_ID
+        // verify belows
+        // - the bundle data of KEY_SATELLITE_COMMUNICATION_ALLOWED is true
+        // - the regionalConfigId is DEFAULT_REGIONAL_SATELLITE_CONFIG_ID
+        logd("testCheckSatelliteAccessRestrictionForLocation : case 3");
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+
+        mSatelliteAccessControllerUT.checkSatelliteAccessRestrictionForLocation(mMockLocation0);
+        verify(mMockResultReceiver, times(3))
+                .send(mResultCodeIntCaptor.capture(), bundleCaptor.capture());
+        assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS), mResultCodeIntCaptor.getValue());
+        assertTrue(bundleCaptor.getValue().getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED));
+        verify(mMockCachedAccessRestrictionMap, times(1))
+                .put(any(), regionalConfigIdCaptor.capture());
+
+        assertEquals(Integer.valueOf(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID),
+                regionalConfigIdCaptor.getValue());
+        assertEquals(Integer.valueOf(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID),
+                mSatelliteAccessControllerUT.getNewRegionalConfigId());
+        assertEquals(Integer.valueOf(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID),
+                mSatelliteAccessControllerUT.getRegionalConfigId());
+
+
+        // when mMockCachedAccessRestrictionMap is not hit and regionalConfigId is null
+        // verify belows
+        // - the bundle data of KEY_SATELLITE_COMMUNICATION_ALLOWED is false
+        // - the regionalConfigId is null
+        logd("testCheckSatelliteAccessRestrictionForLocation : case 4");
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(null);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+
+        mSatelliteAccessControllerUT.checkSatelliteAccessRestrictionForLocation(mMockLocation0);
+        verify(mMockResultReceiver, times(4))
+                .send(mResultCodeIntCaptor.capture(), bundleCaptor.capture());
+        assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS), mResultCodeIntCaptor.getValue());
+        assertFalse(bundleCaptor.getValue().getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED));
+        verify(mMockCachedAccessRestrictionMap, times(1))
+                .put(any(), regionalConfigIdCaptor.capture());
+        assertNull(regionalConfigIdCaptor.getValue());
+        assertNull(mSatelliteAccessControllerUT.getNewRegionalConfigId());
+        assertNull(mSatelliteAccessControllerUT.getRegionalConfigId());
+    }
+
     @Test
     public void testIsRegionDisallowed() throws Exception {
         // setup to make the return value of mQueriedSatelliteAllowed 'true'
@@ -531,7 +858,8 @@
         replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
                 mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
         doReturn(true).when(mMockCachedAccessRestrictionMap).containsKey(any());
-        doReturn(true).when(mMockCachedAccessRestrictionMap).get(any());
+        doReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID)
+                .when(mMockCachedAccessRestrictionMap).get(any());
 
         // get allowed country codes EMPTY from resources
         when(mMockResources.getStringArray(
@@ -946,7 +1274,6 @@
         // current time is greater than the location query throttle interval
         // verify mMockLocationManager.getCurrentLocation() is invoked
         // verify time(mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos) is updated
-        logd("youngcha 1");
         clearInvocations(mMockLocationManager);
         mSatelliteAccessControllerUT.setLocationRequestCancellationSignalAsNull(true);
         mSatelliteAccessControllerUT.elapsedRealtimeNanos =
@@ -1254,10 +1581,10 @@
     @Test
     public void testHandleIsSatelliteSupportedResult() throws Exception {
         // Setup for this test case
-        Iterator<ResultReceiver> mockIterator = mock(Iterator.class);
-        doReturn(mockIterator).when(mMockSatelliteAllowResultReceivers).iterator();
-        doReturn(true, false).when(mockIterator).hasNext();
-        doReturn(mMockSatelliteSupportedResultReceiver).when(mockIterator).next();
+        Iterator<ResultReceiver> mockResultReceiverIterator = mock(Iterator.class);
+        doReturn(mockResultReceiverIterator).when(mMockSatelliteAllowResultReceivers).iterator();
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        doReturn(mMockResultReceiver).when(mockResultReceiverIterator).next();
 
         replaceInstance(SatelliteAccessController.class, "mSatelliteAllowResultReceivers",
                 mSatelliteAccessControllerUT, mMockSatelliteAllowResultReceivers);
@@ -1266,10 +1593,10 @@
         // case that resultCode is not SATELLITE_RESULT_SUCCESS
         int resultCode = SATELLITE_RESULT_ERROR;
         Bundle bundle = new Bundle();
-        doReturn(true, false).when(mockIterator).hasNext();
-        clearInvocations(mMockSatelliteSupportedResultReceiver);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        clearInvocations(mMockResultReceiver);
         mSatelliteAccessControllerUT.handleIsSatelliteSupportedResult(resultCode, bundle);
-        verify(mMockSatelliteSupportedResultReceiver)
+        verify(mMockResultReceiver)
                 .send(mResultCodeIntCaptor.capture(), any());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_ERROR), mResultCodeIntCaptor.getValue());
 
@@ -1277,20 +1604,19 @@
         // verify that the resultCode is delivered as it were
         resultCode = SATELLITE_RESULT_SUCCESS;
         bundle.putBoolean(KEY_SATELLITE_PROVISIONED, false);
-        doReturn(true, false).when(mockIterator).hasNext();
-        clearInvocations(mMockSatelliteSupportedResultReceiver);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        clearInvocations(mMockResultReceiver);
         mSatelliteAccessControllerUT.handleIsSatelliteSupportedResult(resultCode, bundle);
-        verify(mMockSatelliteSupportedResultReceiver)
-                .send(mResultCodeIntCaptor.capture(), any());
+        verify(mMockResultReceiver).send(mResultCodeIntCaptor.capture(), any());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS), mResultCodeIntCaptor.getValue());
 
         // case KEY_SATELLITE_SUPPORTED is false
         // verify SATELLITE_RESULT_NOT_SUPPORTED is captured
         bundle.putBoolean(KEY_SATELLITE_SUPPORTED, false);
-        doReturn(true, false).when(mockIterator).hasNext();
-        clearInvocations(mMockSatelliteSupportedResultReceiver);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        clearInvocations(mMockResultReceiver);
         mSatelliteAccessControllerUT.handleIsSatelliteSupportedResult(resultCode, bundle);
-        verify(mMockSatelliteSupportedResultReceiver)
+        verify(mMockResultReceiver)
                 .send(mResultCodeIntCaptor.capture(), mResultDataBundleCaptor.capture());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_NOT_SUPPORTED),
                 mResultCodeIntCaptor.getValue());
@@ -1302,10 +1628,10 @@
         bundle.putBoolean(KEY_SATELLITE_SUPPORTED, true);
         when(mMockCountryDetector.getCurrentNetworkCountryIso())
                 .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_KR));
-        doReturn(true, false).when(mockIterator).hasNext();
-        clearInvocations(mMockSatelliteSupportedResultReceiver);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        clearInvocations(mMockResultReceiver);
         mSatelliteAccessControllerUT.handleIsSatelliteSupportedResult(resultCode, bundle);
-        verify(mMockSatelliteSupportedResultReceiver)
+        verify(mMockResultReceiver)
                 .send(mResultCodeIntCaptor.capture(), mResultDataBundleCaptor.capture());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_SUCCESS),
                 mResultCodeIntCaptor.getValue());
@@ -1317,10 +1643,10 @@
         when(mMockCountryDetector.getCurrentNetworkCountryIso())
                 .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_US));
         doReturn(false).when(mMockLocationManager).isLocationEnabled();
-        doReturn(true, false).when(mockIterator).hasNext();
-        clearInvocations(mMockSatelliteSupportedResultReceiver);
+        doReturn(true, false).when(mockResultReceiverIterator).hasNext();
+        clearInvocations(mMockResultReceiver);
         mSatelliteAccessControllerUT.handleIsSatelliteSupportedResult(resultCode, bundle);
-        verify(mMockSatelliteSupportedResultReceiver)
+        verify(mMockResultReceiver)
                 .send(mResultCodeIntCaptor.capture(), mResultDataBundleCaptor.capture());
         assertEquals(Integer.valueOf(SATELLITE_RESULT_LOCATION_DISABLED),
                 mResultCodeIntCaptor.getValue());
@@ -1367,7 +1693,7 @@
 
     private void sendSatelliteCommunicationAllowedEvent() {
         Pair<Integer, ResultReceiver> requestPair =
-                new Pair<>(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                new Pair<>(DEFAULT_SUBSCRIPTION_ID,
                         mSatelliteAccessControllerUT.getResultReceiverCurrentLocation());
         Message msg = mSatelliteAccessControllerUT.obtainMessage(
                 CMD_IS_SATELLITE_COMMUNICATION_ALLOWED);
@@ -1567,5 +1893,25 @@
                 return mCurrentSatelliteAllowedState;
             }
         }
+
+        @Nullable
+        public Integer getRegionalConfigId() {
+            synchronized (mLock) {
+                return mRegionalConfigId;
+            }
+        }
+
+        @Nullable
+        public Integer getNewRegionalConfigId() {
+            synchronized (mLock) {
+                return mNewRegionalConfigId;
+            }
+        }
+
+        public void setRegionalConfigId(@Nullable Integer regionalConfigId) {
+            synchronized (mLock) {
+                mRegionalConfigId = regionalConfigId;
+            }
+        }
     }
 }
diff --git a/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java b/tests/src/com/android/phone/satellite/entitlement/SatelliteEntitlementControllerTest.java
index 11f982e..9f8a733 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;
@@ -74,7 +73,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
@@ -87,7 +85,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 +100,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,10 +115,10 @@
     private TestableLooper mTestableLooper;
     private List<Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener>>
             mCarrierConfigChangedListenerList = new ArrayList<>();
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        MockitoAnnotations.initMocks(this);
 
         replaceInstance(SubscriptionManagerService.class, "sInstance", null,
                 mMockSubscriptionManagerService);
@@ -129,14 +126,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 +158,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 +171,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 +245,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 +335,6 @@
 
     @Test
     public void testCheckSatelliteEntitlementStatusWhenInternetConnected() throws Exception {
-        logd("testCheckSatelliteEntitlementStatusWhenInternetConnected");
         ConnectivityManager.NetworkCallback networkCallback =
                 (ConnectivityManager.NetworkCallback) getValue("mNetworkCallback");
         Network mockNetwork = mock(Network.class);
@@ -369,7 +356,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 +372,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 +385,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 +455,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 +468,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 +537,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error500() throws Exception {
-        logd("testStartQueryEntitlementStatus_error500");
         setIsQueryAvailableTrue();
         Map<Integer, Integer> retryCountPerSub =
                 (Map<Integer, Integer>) getValue("mRetryCountPerSub");
@@ -569,7 +552,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_retrySuccess() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_retrySuccess");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
         Map<Integer, Integer> retryCountPerSub =
@@ -597,7 +579,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 +603,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 +618,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 +679,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 +708,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 +735,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_error500() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_error500");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
 
@@ -782,7 +759,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_error503_otherError() throws Exception {
-        logd("testStartQueryEntitlementStatus_error503_otherError");
         setIsQueryAvailableTrue();
         set503RetryAfterResponse();
 
@@ -820,7 +796,6 @@
 
     @Test
     public void testStartQueryEntitlementStatus_AfterSimRefresh() throws Exception {
-        logd("testStartQueryEntitlementStatus_AfterSimRefresh");
         setIsQueryAvailableTrue();
 
         // Verify the first query complete.
@@ -959,12 +934,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/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
index 71a23e6..fe6d6f7 100644
--- a/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
+++ b/tests/src/com/android/services/telephony/DisconnectCauseUtilTest.java
@@ -22,7 +22,6 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.TestCase.assertEquals;
 
-import static org.mockito.Mockito.mock;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
@@ -38,15 +37,11 @@
 
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.CallFailCause;
-import com.android.internal.telephony.GsmCdmaPhone;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
 import com.android.phone.R;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 
 import java.util.Locale;
 
@@ -57,13 +52,6 @@
     public static final int PHONE_ID = 123;
     public static final String EMPTY_STRING = "";
 
-    // dynamic
-    private Context mContext;
-
-    //Mocks
-    @Mock
-    private GsmCdmaPhone mMockPhone;
-
     private final FlagsAdapter mFeatureFlags = new FlagsAdapter(){
         @Override
         public boolean doNotOverridePreciseLabel() {
@@ -74,11 +62,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        // objects that call static getInstance()
-        mMockPhone = mock(GsmCdmaPhone.class);
-        mContext = InstrumentationRegistry.getTargetContext();
-        // set mocks
-        setSinglePhone();
     }
 
     /**
@@ -253,11 +236,6 @@
         return config;
     }
 
-    private void setSinglePhone() throws Exception {
-        Phone[] mPhones = new Phone[]{mMockPhone};
-        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
-    }
-
     private Resources getResourcesForLocale(Context context, Locale locale) {
         Configuration config = new Configuration();
         config.setToDefaults();
@@ -268,7 +246,7 @@
 
     private void safeAssertLabel(Integer resourceId,
             android.telecom.DisconnectCause disconnectCause) {
-        Resources r = getResourcesForLocale(mContext, Locale.US);
+        Resources r = getResourcesForLocale(InstrumentationRegistry.getTargetContext(), Locale.US);
         if (resourceId == null || r == null) {
             return;
         }
diff --git a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
index b1572f1..eacb001 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
@@ -25,21 +25,27 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
-import android.os.Looper;
+import android.content.pm.PackageManager;
 import android.telecom.PhoneAccountHandle;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
+import com.android.TelephonyTestBase;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 /**
  * Tests the functionality in ImsConferenceController.java
  */
-
-public class ImsConferenceControllerTest {
+@RunWith(AndroidJUnit4.class)
+public class ImsConferenceControllerTest extends TelephonyTestBase {
+    @Mock
+    PackageManager mPackageManager;
 
     @Mock
     private TelephonyConnectionServiceProxy mMockTelephonyConnectionServiceProxy;
@@ -64,11 +70,14 @@
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-        mTelecomAccountRegistry = TelecomAccountRegistry.getInstance(null);
+        super.setUp();
+
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING))
+                .thenReturn(true);
+
+        mTelecomAccountRegistry = TelecomAccountRegistry.getInstance(mContext);
         mTestTelephonyConnectionA = new TestTelephonyConnection();
         mTestTelephonyConnectionB = new TestTelephonyConnection();
 
@@ -79,6 +88,11 @@
                 mMockTelephonyConnectionServiceProxy, () -> false);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
     /**
      * Behavior: add telephony connections B and A to conference controller,
      *           set status for connections, remove one call
diff --git a/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java b/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java
index a8a54f8..d0fc69d 100644
--- a/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java
+++ b/tests/src/com/android/services/telephony/TelecomAccountRegistryTest.java
@@ -50,10 +50,8 @@
 import com.android.TelephonyTestBase;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.SimultaneousCallingTracker;
 import com.android.internal.telephony.flags.Flags;
-import com.android.phone.PhoneGlobals;
 import com.android.phone.PhoneInterfaceManager;
 import com.android.phone.R;
 
@@ -65,7 +63,6 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -85,7 +82,6 @@
     @Mock ImsManager mImsManager;
     @Mock SubscriptionManager mSubscriptionManager;
     @Mock ContentProvider mContentProvider;
-    @Mock PhoneGlobals mPhoneGlobals;
     @Mock Phone mPhone;
     @Mock Resources mResources;
     @Mock Drawable mDrawable;
@@ -98,18 +94,13 @@
     private BroadcastReceiver mUserSwitchedAndConfigChangedReceiver;
     private BroadcastReceiver mLocaleChangedBroadcastReceiver;
     private ContentResolver mContentResolver;
-    private Phone[] mPhones;
     private TestableLooper mTestableLooper;
 
     @Before
     public void setUp() throws Exception {
         super.setUp();
         mSetFlagsRule.disableFlags(Flags.FLAG_DELAY_PHONE_ACCOUNT_REGISTRATION);
-        MockitoAnnotations.initMocks(this);
 
-        mPhones = new Phone[]{mPhone};
-        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
-        replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
         replaceInstance(PhoneInterfaceManager.class, "sInstance", null, mPhoneInterfaceManager);
         when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM);
         when(mPhone.getContext()).thenReturn(mMockedContext);
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 5618770..6a10d75 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -61,7 +61,6 @@
 import android.os.AsyncResult;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.telecom.Conference;
 import android.telecom.Conferenceable;
@@ -283,7 +282,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        doReturn(Looper.getMainLooper()).when(mContext).getMainLooper();
+
         mTestConnectionService = new TestTelephonyConnectionService(mContext);
         mTestConnectionService.setFeatureFlags(mFeatureFlags);
         mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index d91435c..9f1a0ec 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -16,27 +16,31 @@
 
 package com.android.services.telephony;
 
-import android.content.AttributionSource;
-import android.content.ContentResolver;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.content.AttributionSource;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.VideoProfile;
 import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
 
 import com.android.ims.ImsCall;
 import com.android.internal.telephony.Call;
@@ -70,9 +74,6 @@
     Context mMockContext;
 
     @Mock
-    ContentResolver mMockContentResolver;
-
-    @Mock
     Resources mMockResources;
 
     @Mock
@@ -96,6 +97,7 @@
     @Mock
     CarrierConfigManager mCarrierConfigManager;
 
+    private MockContentResolver mMockContentResolver;
     private boolean mIsImsConnection;
     private boolean mIsImsExternalConnection;
     private boolean mIsConferenceSupported = true;
@@ -136,6 +138,14 @@
         mMockContext = mock(Context.class);
         mMockTelephonyManager = mock(TelephonyManager.class);
         mOriginalConnection = mMockRadioConnection;
+
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+        doReturn(applicationInfo).when(mMockContext).getApplicationInfo();
+        mMockContentResolver = new MockContentResolver(mMockContext);
+        mMockContentResolver.addProvider(Settings.AUTHORITY,
+                new EmptyContentProvider(mMockContext));
+
         // Set up mMockRadioConnection and mMockPhone to contain an active call
         when(mMockRadioConnection.getState()).thenReturn(Call.State.ACTIVE);
         when(mOriginalConnection.getState()).thenReturn(Call.State.ACTIVE);
@@ -159,8 +169,7 @@
         when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
                 .thenReturn(mMockTelephonyManager);
         when(mMockContext.getAttributionSource()).thenReturn(attributionSource);
-        when(mMockContentResolver.getUserId()).thenReturn(UserHandle.USER_CURRENT);
-        when(mMockContentResolver.getAttributionSource()).thenReturn(attributionSource);
+        when(mMockContext.getUserId()).thenReturn(UserHandle.USER_CURRENT);
         when(mMockResources.getBoolean(anyInt())).thenReturn(false);
         when(mMockPhone.getDefaultPhone()).thenReturn(mMockPhone);
         when(mMockPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_IMS);
@@ -320,4 +329,15 @@
     public void setMockImsPhoneConnection(ImsPhoneConnection connection) {
         mImsPhoneConnection = connection;
     }
+
+    static class EmptyContentProvider extends MockContentProvider {
+        EmptyContentProvider(Context context) {
+            super(context);
+        }
+
+        @Override
+        public Bundle call(String method, String request, Bundle args) {
+            return new Bundle();
+        }
+    }
 }
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
index 07c9fd0..649d3dd 100644
--- a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -45,6 +45,7 @@
 import com.android.ims.FeatureConnector;
 import com.android.ims.RcsFeatureManager;
 import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper;
+import com.android.phone.ImsStateCallbackController;
 
 import org.junit.After;
 import org.junit.Before;
@@ -84,6 +85,9 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
+
+        replaceInstance(ImsStateCallbackController.class, "sInstance", null,
+                mock(ImsStateCallbackController.class));
     }
 
     @After
diff --git a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
index 42a45f4..df7a37e 100644
--- a/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/SipTransportControllerTest.java
@@ -147,12 +147,16 @@
 
     @After
     public void tearDown() throws Exception {
-        super.tearDown();
-        boolean isShutdown = mExecutorService == null || mExecutorService.isShutdown();
-        if (!isShutdown) {
+        var monitor = RcsProvisioningMonitor.getInstance();
+        if (monitor != null) {
+            monitor.overrideImsFeatureValidation(TEST_SUB_ID, null);
+        }
+
+        if (mExecutorService != null && !mExecutorService.isShutdown()) {
             mExecutorService.shutdownNow();
         }
-        RcsProvisioningMonitor.getInstance().overrideImsFeatureValidation(TEST_SUB_ID, null);
+
+        super.tearDown();
     }
 
     @SmallTest
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
index 4cabf95..34ed5c6 100644
--- a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -40,6 +41,7 @@
 import com.android.ims.RcsFeatureManager;
 import com.android.internal.telephony.ISub;
 import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.phone.ImsStateCallbackController;
 
 import org.junit.After;
 import org.junit.Before;
@@ -103,6 +105,9 @@
                 eq(1), anyInt());
         doReturn(true).when(mResourceProxy).getDeviceUceEnabled(any());
 
+        replaceInstance(ImsStateCallbackController.class, "sInstance", null,
+                mock(ImsStateCallbackController.class));
+
         replaceInstance(TelephonyManager.class, "sInstance", null, mTelephonyManager);
         doReturn(2).when(mTelephonyManager).getActiveModemCount();
     }
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/PopulatedSuffixTableBlock.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
index 2feccbf..8cb9d1d 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
@@ -58,7 +58,8 @@
             SatS2RangeFileFormat fileFormat, IntValueTypedPackedTable packedTable) {
         mFileFormat = Objects.requireNonNull(fileFormat);
         mPackedTable = Objects.requireNonNull(packedTable);
-        mSuffixTableSharedData = SuffixTableSharedData.fromBytes(packedTable.getSharedData());
+        mSuffixTableSharedData = SuffixTableSharedData.fromTypedData(
+                packedTable.getSharedDataAsTyped(), fileFormat);
 
         // Obtain the prefix. All cellIds in this table will share the same prefix except for end
         // range values (which are exclusive so can be for mPrefix + 1 with a suffix value of 0).
@@ -189,7 +190,8 @@
                     endCellIdSuffix = 0;
                 }
                 long endCellId = mFileFormat.createCellId(endCellPrefixValue, endCellIdSuffix);
-                mSuffixTableRange = new SuffixTableRange(startCellId, endCellId);
+                int entryValue = getEntryValue();
+                mSuffixTableRange = new SuffixTableRange(startCellId, endCellId, entryValue);
             }
             return mSuffixTableRange;
         }
@@ -217,5 +219,9 @@
                     + "mSuffixTableEntry=" + mSuffixTableEntry
                     + '}';
         }
+
+        private int getEntryValue() {
+            return mSuffixTableSharedData.getEntryValue(mSuffixTableEntry.getIndex());
+        }
     }
 }
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/SatS2RangeFileReaderTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
index 2797b77..6de40e1 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
@@ -17,6 +17,7 @@
 package com.android.telephony.sats2range;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SatS2RangeFileReader;
@@ -78,4 +79,67 @@
             assertEquals(expectedRange3, range3);
         }
     }
+
+    @Test
+    public void findEntryByCellIdWithEntryValue() throws IOException {
+        final boolean isAllowedList = true;
+        final int entryValueSizeInBytes = 4;
+        final int versionNumber = 0;
+        final int entryValue1 = 1;
+        final int entryValue2 = 2;
+        final int entryValue3 = 3;
+
+        File file = File.createTempFile("test", ".dat");
+        SatS2RangeFileFormat fileFormat;
+
+        SuffixTableRange expectedRange1, expectedRange2, expectedRange3;
+        try (SatS2RangeFileWriter satS2RangeFileWriter = SatS2RangeFileWriter.open(file,
+                TestUtils.createS2RangeFileFormat(isAllowedList, entryValueSizeInBytes,
+                        versionNumber))) {
+            fileFormat = satS2RangeFileWriter.getFileFormat();
+
+            // Two ranges that share a prefix.
+            expectedRange1 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 1000),
+                    TestUtils.createCellId(fileFormat, 1, 1000, 2000),
+                    entryValue1);
+            expectedRange2 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 2000),
+                    TestUtils.createCellId(fileFormat, 1, 1000, 3000),
+                    entryValue2);
+            // This range has a different prefix, so will be in a different suffix table.
+            expectedRange3 = new SuffixTableRange(
+                    TestUtils.createCellId(fileFormat, 1, 1001, 1000),
+                    TestUtils.createCellId(fileFormat, 1, 1001, 2000),
+                    entryValue3);
+
+            List<SuffixTableRange> ranges = new ArrayList<>();
+            ranges.add(expectedRange1);
+            ranges.add(expectedRange2);
+            ranges.add(expectedRange3);
+            satS2RangeFileWriter.createSortedSuffixBlocks(ranges.iterator());
+        }
+
+        try (SatS2RangeFileReader satS2RangeFileReader = SatS2RangeFileReader.open(file)) {
+            assertEquals(isAllowedList, satS2RangeFileReader.isAllowedList());
+
+            SuffixTableRange range1 = satS2RangeFileReader.findEntryByCellId(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 1500));
+            assertNotNull(range1);
+            assertEquals(expectedRange1, range1);
+            assertEquals(entryValue1, range1.getEntryValue());
+
+            SuffixTableRange range2 = satS2RangeFileReader.findEntryByCellId(
+                    TestUtils.createCellId(fileFormat, 1, 1000, 2500));
+            assertNotNull(range2);
+            assertEquals(expectedRange2, range2);
+            assertEquals(entryValue2, range2.getEntryValue());
+
+            SuffixTableRange range3 = satS2RangeFileReader.findEntryByCellId(
+                    TestUtils.createCellId(fileFormat, 1, 1001, 1500));
+            assertNotNull(range3);
+            assertEquals(expectedRange3, range3);
+            assertEquals(entryValue3, range3.getEntryValue());
+        }
+    }
 }
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/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java b/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
index 3dfc720..ca0b754 100644
--- a/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
+++ b/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
@@ -38,6 +38,14 @@
 
     /** Returns a valid {@link SatS2RangeFileFormat}. */
     public static SatS2RangeFileFormat createS2RangeFileFormat(boolean isAllowedList) {
+        return createS2RangeFileFormat(isAllowedList,
+                /* entryValueSizeInBytes */0,
+                /* versionNumber */0);
+    }
+
+    /** Returns a valid {@link SatS2RangeFileFormat}. */
+    public static SatS2RangeFileFormat createS2RangeFileFormat(boolean isAllowedList,
+            int entryValueSizeInBytes, int versionNumber) {
         int dataS2Level = TEST_S2_LEVEL;
         int faceIdBits = 3;
         int bitCountPerLevel = 2;
@@ -48,7 +56,8 @@
         int suffixTableEntryBitCount = 4 * Byte.SIZE;
         int suffixTableBlockIdOffset = 5;
         return new SatS2RangeFileFormat(dataS2Level, prefixBitCount, suffixBitCount,
-                suffixTableBlockIdOffset, suffixTableEntryBitCount, isAllowedList);
+                suffixTableBlockIdOffset, suffixTableEntryBitCount, isAllowedList,
+                entryValueSizeInBytes, versionNumber);
     }
 
     /** Create an S2 cell ID */
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/SatS2RangeFileWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
index 3018aec..375707a 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
@@ -168,36 +168,16 @@
             // Add an empty block.
             blockWriter = SuffixTableWriter.createEmptyBlockWriter();
         } else {
+            List<SuffixTableRange> suffixTableRanges = convertSamePrefixRangesToSuffixTableRanges(
+                    samePrefixRanges);
+            List<Integer> entryValues = getEntryValues(suffixTableRanges);
             // Create a suffix table block.
-            SuffixTableSharedData sharedData = new SuffixTableSharedData(currentPrefix);
+            SuffixTableSharedData sharedData = new SuffixTableSharedData(currentPrefix, entryValues,
+                    mFileFormat);
             SuffixTableWriter suffixTableWriter =
                     SuffixTableWriter.createPopulated(mFileFormat, sharedData);
-            SuffixTableRange lastRange = null;
-            for (SuffixTableRange currentRange : samePrefixRanges) {
-                // Validate ranges don't overlap.
-                if (lastRange != null) {
-                    if (lastRange.overlaps(currentRange)) {
-                        throw new IllegalStateException("lastRange=" + lastRange + " overlaps"
-                                + " currentRange=" + currentRange);
-                    }
-                }
-                lastRange = currentRange;
-
-                // Split the range so it fits.
-                final int maxRangeLength = mFileFormat.getTableEntryMaxRangeLengthValue();
-                long startCellId = currentRange.getStartCellId();
-                long endCellId = currentRange.getEndCellId();
-                int rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
-                while (rangeLength > maxRangeLength) {
-                    long newEndCellId = S2Support.offsetCellId(startCellId, maxRangeLength);
-                    SuffixTableRange suffixTableRange = new SuffixTableRange(startCellId,
-                            newEndCellId);
-                    suffixTableWriter.addRange(suffixTableRange);
-                    startCellId = newEndCellId;
-                    rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
-                }
-                SuffixTableRange suffixTableRange = new SuffixTableRange(startCellId, endCellId);
-                suffixTableWriter.addRange(suffixTableRange);
+            for (SuffixTableRange range : suffixTableRanges) {
+                suffixTableWriter.addRange(range);
             }
             blockWriter = suffixTableWriter;
         }
@@ -237,4 +217,48 @@
     public SatS2RangeFileFormat getFileFormat() {
         return mFileFormat;
     }
+
+    private List<SuffixTableRange> convertSamePrefixRangesToSuffixTableRanges(
+            List<SuffixTableRange> samePrefixRanges) {
+        List<SuffixTableRange> suffixTableRanges = new ArrayList<>();
+        SuffixTableRange lastRange = null;
+        for (SuffixTableRange currentRange : samePrefixRanges) {
+            // Validate ranges don't overlap.
+            if (lastRange != null) {
+                if (lastRange.overlaps(currentRange)) {
+                    throw new IllegalStateException("lastRange=" + lastRange + " overlaps"
+                            + " currentRange=" + currentRange);
+                }
+            }
+            lastRange = currentRange;
+            int entryValue = currentRange.getEntryValue();
+
+            // Split the range so it fits.
+            final int maxRangeLength = mFileFormat.getTableEntryMaxRangeLengthValue();
+            long startCellId = currentRange.getStartCellId();
+            long endCellId = currentRange.getEndCellId();
+            int rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
+            while (rangeLength > maxRangeLength) {
+                long newEndCellId = S2Support.offsetCellId(startCellId, maxRangeLength);
+                SuffixTableRange suffixTableRange =
+                        new SuffixTableRange(startCellId, newEndCellId, entryValue);
+                suffixTableRanges.add(suffixTableRange);
+                startCellId = newEndCellId;
+                rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
+            }
+            SuffixTableRange suffixTableRange =
+                    new SuffixTableRange(startCellId, endCellId, entryValue);
+            suffixTableRanges.add(suffixTableRange);
+        }
+        return suffixTableRanges;
+    }
+
+    private List<Integer> getEntryValues(List<SuffixTableRange> suffixTableRanges) {
+        List<Integer> entryValues = new ArrayList<>();
+        for (SuffixTableRange suffixTableRange : suffixTableRanges) {
+            entryValues.add(suffixTableRange.getEntryValue());
+        }
+        return entryValues;
+    }
+
 }
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) {