• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.satellite;
18 
19 import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
20 import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
21 import static android.provider.Settings.ACTION_SATELLITE_SETTING;
22 import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC;
23 import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL;
24 import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_TYPE;
25 import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL;
26 import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT;
27 import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT;
28 import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY;
29 import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT;
30 import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
31 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
32 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL;
33 import static android.telephony.CarrierConfigManager.KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE;
34 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
35 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT;
36 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
37 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_DATA_SUPPORT_MODE_INT;
38 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_DISPLAY_NAME_STRING;
39 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
40 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
41 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_NIDD_APN_NAME_STRING;
42 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT;
43 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT;
44 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL;
45 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT;
46 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL;
47 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE_BYTES_INT;
48 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY;
49 import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
50 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
51 import static android.telephony.SubscriptionManager.isValidSubscriptionId;
52 import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
53 import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
54 import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
55 import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
56 import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
57 import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT;
58 import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
59 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS;
60 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
61 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR;
62 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
63 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION;
64 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED;
65 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
66 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
67 
68 import static com.android.internal.telephony.configupdate.ConfigProviderAdaptor.DOMAIN_SATELLITE;
69 
70 import android.annotation.ArrayRes;
71 import android.annotation.IntDef;
72 import android.annotation.NonNull;
73 import android.annotation.Nullable;
74 import android.app.AlertDialog;
75 import android.app.Notification;
76 import android.app.NotificationChannel;
77 import android.app.NotificationManager;
78 import android.app.PendingIntent;
79 import android.app.StatusBarManager;
80 import android.bluetooth.BluetoothAdapter;
81 import android.content.BroadcastReceiver;
82 import android.content.ComponentName;
83 import android.content.ContentResolver;
84 import android.content.Context;
85 import android.content.Intent;
86 import android.content.IntentFilter;
87 import android.content.SharedPreferences;
88 import android.content.pm.ApplicationInfo;
89 import android.content.pm.PackageManager;
90 import android.content.res.Configuration;
91 import android.content.res.Resources;
92 import android.database.ContentObserver;
93 import android.hardware.devicestate.DeviceState;
94 import android.hardware.devicestate.DeviceStateManager;
95 import android.location.LocationManager;
96 import android.net.Uri;
97 import android.net.wifi.WifiManager;
98 import android.nfc.NfcAdapter;
99 import android.os.AsyncResult;
100 import android.os.Binder;
101 import android.os.Build;
102 import android.os.Bundle;
103 import android.os.CancellationSignal;
104 import android.os.Handler;
105 import android.os.HandlerExecutor;
106 import android.os.HandlerThread;
107 import android.os.IBinder;
108 import android.os.ICancellationSignal;
109 import android.os.Looper;
110 import android.os.Message;
111 import android.os.PersistableBundle;
112 import android.os.Registrant;
113 import android.os.RegistrantList;
114 import android.os.RemoteException;
115 import android.os.ResultReceiver;
116 import android.os.ServiceSpecificException;
117 import android.os.SystemClock;
118 import android.os.SystemProperties;
119 import android.os.UserHandle;
120 import android.provider.Settings;
121 import android.provider.Telephony;
122 import android.telecom.TelecomManager;
123 import android.telephony.AccessNetworkConstants;
124 import android.telephony.AnomalyReporter;
125 import android.telephony.CarrierConfigManager;
126 import android.telephony.DropBoxManagerLoggerBackend;
127 import android.telephony.NetworkRegistrationInfo;
128 import android.telephony.PersistentLogger;
129 import android.telephony.Rlog;
130 import android.telephony.ServiceState;
131 import android.telephony.SubscriptionInfo;
132 import android.telephony.SubscriptionManager;
133 import android.telephony.TelephonyManager;
134 import android.telephony.TelephonyRegistryManager;
135 import android.telephony.satellite.INtnSignalStrengthCallback;
136 import android.telephony.satellite.ISatelliteCapabilitiesCallback;
137 import android.telephony.satellite.ISatelliteDatagramCallback;
138 import android.telephony.satellite.ISatelliteModemStateCallback;
139 import android.telephony.satellite.ISatelliteProvisionStateCallback;
140 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
141 import android.telephony.satellite.ISelectedNbIotSatelliteSubscriptionCallback;
142 import android.telephony.satellite.NtnSignalStrength;
143 import android.telephony.satellite.SatelliteAccessConfiguration;
144 import android.telephony.satellite.SatelliteCapabilities;
145 import android.telephony.satellite.SatelliteCommunicationAccessStateCallback;
146 import android.telephony.satellite.SatelliteDatagram;
147 import android.telephony.satellite.SatelliteManager;
148 import android.telephony.satellite.SatelliteModemEnableRequestAttributes;
149 import android.telephony.satellite.SatelliteSubscriberInfo;
150 import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
151 import android.telephony.satellite.SatelliteSubscriptionInfo;
152 import android.telephony.satellite.SystemSelectionSpecifier;
153 import android.text.TextUtils;
154 import android.util.Log;
155 import android.util.Pair;
156 import android.util.SparseArray;
157 import android.util.SparseBooleanArray;
158 import android.uwb.UwbManager;
159 import android.view.WindowManager;
160 
161 import com.android.internal.R;
162 import com.android.internal.annotations.GuardedBy;
163 import com.android.internal.annotations.VisibleForTesting;
164 import com.android.internal.telephony.CommandsInterface;
165 import com.android.internal.telephony.DeviceStateMonitor;
166 import com.android.internal.telephony.IBooleanConsumer;
167 import com.android.internal.telephony.IIntegerConsumer;
168 import com.android.internal.telephony.Phone;
169 import com.android.internal.telephony.PhoneFactory;
170 import com.android.internal.telephony.TelephonyCountryDetector;
171 import com.android.internal.telephony.configupdate.ConfigParser;
172 import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
173 import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
174 import com.android.internal.telephony.flags.FeatureFlags;
175 import com.android.internal.telephony.flags.Flags;
176 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteControllerStats;
177 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteSessionStats;
178 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
179 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
180 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
181 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
182 import com.android.internal.telephony.subscription.SubscriptionManagerService;
183 import com.android.internal.telephony.util.ArrayUtils;
184 import com.android.internal.telephony.util.TelephonyUtils;
185 import com.android.internal.telephony.util.WorkerThread;
186 import com.android.internal.util.FunctionalUtils;
187 
188 import java.lang.annotation.Retention;
189 import java.lang.annotation.RetentionPolicy;
190 import java.util.ArrayList;
191 import java.util.Arrays;
192 import java.util.Collections;
193 import java.util.HashMap;
194 import java.util.HashSet;
195 import java.util.List;
196 import java.util.Map;
197 import java.util.Optional;
198 import java.util.Set;
199 import java.util.TreeMap;
200 import java.util.UUID;
201 import java.util.concurrent.ConcurrentHashMap;
202 import java.util.concurrent.Executors;
203 import java.util.concurrent.TimeUnit;
204 import java.util.concurrent.atomic.AtomicBoolean;
205 import java.util.concurrent.atomic.AtomicLong;
206 import java.util.function.Consumer;
207 import java.util.stream.Collectors;
208 
209 /**
210  * Satellite controller is the backend service of
211  * {@link android.telephony.satellite.SatelliteManager}.
212  */
213 public class SatelliteController extends Handler {
214     private static final String TAG = "SatelliteController";
215     /** Whether enabling verbose debugging message or not. */
216     private static final boolean DBG = false;
217     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
218     private static final boolean DEBUG = !"user".equals(Build.TYPE);
219     /** File used to store shared preferences related to satellite. */
220     public static final String SATELLITE_SHARED_PREF = "satellite_shared_pref";
221     public static final String SATELLITE_SUBSCRIPTION_ID = "satellite_subscription_id";
222     /** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */
223     public static final int SATELLITE_MODE_ENABLED_TRUE = 1;
224     public static final int SATELLITE_MODE_ENABLED_FALSE = 0;
225     public static final int INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE = -1;
226     /**
227      * This is used by CTS to override the timeout duration to wait for the response of the request
228      * to enable satellite.
229      */
230     public static final int TIMEOUT_TYPE_WAIT_FOR_SATELLITE_ENABLING_RESPONSE = 1;
231     /** This is used by CTS to override demo pointing aligned duration. */
232     public static final int TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS = 2;
233     /** This is used by CTS to override demo pointing not aligned duration. */
234     public static final int TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS = 3;
235     /** This is used by CTS to override evaluate esos profiles prioritization duration. */
236     public static final int TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS = 4;
237     /** Key used to read/write OEM-enabled satellite provision status in shared preferences. */
238     private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY =
239             "oem_enabled_satellite_provision_status_key";
240     /** Key used to read/write default messages application NTN SMS support
241      * in shared preferences. */
242     @VisibleForTesting(visibility =  VisibleForTesting.Visibility.PRIVATE)
243     public static final String NTN_SMS_SUPPORTED_BY_MESSAGES_APP_KEY =
244             "ntn_sms_supported_by_messages_app_key";
245     public static final String CARRIER_ROAMING_NTN_ALL_SATELLITE_PLMN_SET_KEY =
246             "carrier_roaming_ntn_all_satellite_plmn_set_key";
247 
248     public static final long DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS =
249             TimeUnit.SECONDS.toMillis(30);
250 
251     /** Sets report entitled metrics cool down to 23 hours to help enforcing privacy requirement.*/
252     private static final long WAIT_FOR_REPORT_ENTITLED_MERTICS_TIMEOUT_MILLIS =
253             TimeUnit.HOURS.toMillis(23);
254 
255     /**
256      * Delay SatelliteEnable request when network selection auto. current RIL not verified to
257      * response right after network selection auto changed. Some RIL has delay for waiting in-svc
258      * with Automatic selection request.
259      */
260     private static final long DELAY_WAITING_SET_NETWORK_SELECTION_AUTO_MILLIS =
261             TimeUnit.SECONDS.toMillis(1);
262 
263     /** Message codes used in handleMessage() */
264     //TODO: Move the Commands and events related to position updates to PointingAppController
265     private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1;
266     private static final int EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE = 2;
267     private static final int CMD_STOP_SATELLITE_TRANSMISSION_UPDATES = 3;
268     private static final int EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE = 4;
269     private static final int CMD_PROVISION_SATELLITE_SERVICE = 7;
270     private static final int EVENT_PROVISION_SATELLITE_SERVICE_DONE = 8;
271     private static final int CMD_DEPROVISION_SATELLITE_SERVICE = 9;
272     private static final int EVENT_DEPROVISION_SATELLITE_SERVICE_DONE = 10;
273     private static final int CMD_SET_SATELLITE_ENABLED = 11;
274     private static final int EVENT_SET_SATELLITE_ENABLED_DONE = 12;
275     private static final int CMD_IS_SATELLITE_ENABLED = 13;
276     private static final int EVENT_IS_SATELLITE_ENABLED_DONE = 14;
277     private static final int CMD_IS_SATELLITE_SUPPORTED = 15;
278     private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16;
279     private static final int CMD_GET_SATELLITE_CAPABILITIES = 17;
280     private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18;
281     private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21;
282     private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22;
283     private static final int EVENT_RADIO_STATE_CHANGED = 23;
284     private static final int CMD_IS_SATELLITE_PROVISIONED = 24;
285     private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25;
286     private static final int EVENT_PENDING_DATAGRAMS = 27;
287     private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28;
288     private static final int EVENT_SET_SATELLITE_PLMN_INFO_DONE = 29;
289     private static final int CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE = 30;
290     private static final int EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE = 31;
291     private static final int CMD_REQUEST_NTN_SIGNAL_STRENGTH = 32;
292     private static final int EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE = 33;
293     private static final int EVENT_NTN_SIGNAL_STRENGTH_CHANGED = 34;
294     private static final int CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING = 35;
295     private static final int EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE = 36;
296     private static final int EVENT_SERVICE_STATE_CHANGED = 37;
297     private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38;
298     protected static final int EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT = 39;
299     private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
300     private static final int EVENT_SATELLITE_SUPPORTED_STATE_CHANGED = 41;
301     private static final int EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT = 42;
302     private static final int CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION = 43;
303     private static final int CMD_UPDATE_PROVISION_SATELLITE_TOKEN = 44;
304     private static final int EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE = 45;
305     private static final int EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT = 46;
306     private static final int EVENT_WIFI_CONNECTIVITY_STATE_CHANGED = 47;
307     protected static final int EVENT_WAIT_FOR_CELLULAR_MODEM_OFF_TIMED_OUT = 49;
308     private static final int CMD_UPDATE_SATELLITE_ENABLE_ATTRIBUTES = 50;
309     private static final int EVENT_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_DONE = 51;
310     protected static final int
311             EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT = 52;
312     private static final int EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT = 53;
313     protected static final int EVENT_SATELLITE_REGISTRATION_FAILURE = 54;
314     private static final int EVENT_TERRESTRIAL_NETWORK_AVAILABLE_CHANGED = 55;
315     private static final int EVENT_SET_NETWORK_SELECTION_AUTO_DONE = 56;
316     private static final int EVENT_SIGNAL_STRENGTH_CHANGED = 57;
317     private static final int CMD_UPDATE_SYSTEM_SELECTION_CHANNELS = 58;
318     private static final int EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE = 59;
319     private static final int EVENT_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_CHANGED = 60;
320     private static final int CMD_EVALUATE_CARRIER_ROAMING_NTN_ELIGIBILITY_CHANGE = 61;
321     private static final int CMD_LOCATION_SERVICE_STATE_CHANGED = 62;
322     protected static final int
323         EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT = 63;
324     private static final int CMD_GET_SATELLITE_ENABLED_FOR_CARRIER = 64;
325     private static final int EVENT_GET_SATELLITE_ENABLED_FOR_CARRIER_DONE = 65;
326 
327     @NonNull private static SatelliteController sInstance;
328     @NonNull private final Context mContext;
329     @NonNull private final SatelliteModemInterface mSatelliteModemInterface;
330     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
331     @NonNull protected SatelliteSessionController mSatelliteSessionController;
332     @NonNull private final PointingAppController mPointingAppController;
333     @NonNull private final DatagramController mDatagramController;
334     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
335     @NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
336     @NonNull private SessionMetricsStats mSessionMetricsStats;
337     @NonNull private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats;
338 
339     @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
340     @NonNull private final TelephonyCountryDetector mCountryDetector;
341     @NonNull private final TelecomManager mTelecomManager;
342     private final CommandsInterface mCi;
343     private ContentResolver mContentResolver;
344     private final DeviceStateMonitor mDSM;
345     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
346     protected final Object mSatellitePhoneLock = new Object();
347     @GuardedBy("mSatellitePhoneLock")
348     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
349     protected Phone mSatellitePhone = null;
350     private SatelliteOptimizedApplicationsTracker mSatelliteOptimizedApplicationsTracker;
351     private final Object mRadioStateLock = new Object();
352 
353     /** Flags to indicate whether the respective radio is enabled */
354     @GuardedBy("mRadioStateLock")
355     private boolean mBTStateEnabled = false;
356     @GuardedBy("mRadioStateLock")
357     private boolean mNfcStateEnabled = false;
358     @GuardedBy("mRadioStateLock")
359     private boolean mUwbStateEnabled = false;
360     @GuardedBy("mRadioStateLock")
361     private boolean mWifiStateEnabled = false;
362 
363     // Flags to indicate that respective radios need to be disabled when satellite is enabled
364     private boolean mDisableBTOnSatelliteEnabled = false;
365     private boolean mDisableNFCOnSatelliteEnabled = false;
366     private boolean mDisableUWBOnSatelliteEnabled = false;
367     private boolean mDisableWifiOnSatelliteEnabled = false;
368     private AtomicBoolean mIgnorePlmnListFromStorage = new AtomicBoolean(false);
369 
370     private final Object mSatelliteEnabledRequestLock = new Object();
371     /* This variable is used to store the first enable request that framework has received in the
372      * current session.
373      */
374     @GuardedBy("mSatelliteEnabledRequestLock")
375     private RequestSatelliteEnabledArgument mSatelliteEnabledRequest = null;
376     /* This variable is used to store a disable request that framework has received.
377      */
378     @GuardedBy("mSatelliteEnabledRequestLock")
379     private RequestSatelliteEnabledArgument mSatelliteDisabledRequest = null;
380     /* This variable is used to store an enable request that updates the enable attributes of an
381      * existing satellite session.
382      */
383     @GuardedBy("mSatelliteEnabledRequestLock")
384     private RequestSatelliteEnabledArgument mSatelliteEnableAttributesUpdateRequest = null;
385     /** Flag to indicate that satellite is enabled successfully
386      * and waiting for all the radios to be disabled so that success can be sent to callback
387      */
388     @GuardedBy("mSatelliteEnabledRequestLock")
389     private boolean mWaitingForRadioDisabled = false;
390     @GuardedBy("mSatelliteEnabledRequestLock")
391     private boolean mWaitingForDisableSatelliteModemResponse = false;
392     @GuardedBy("mSatelliteEnabledRequestLock")
393     private boolean mWaitingForSatelliteModemOff = false;
394 
395     private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService =
396             new AtomicBoolean(false);
397     private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService =
398             new AtomicBoolean(false);
399     private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false);
400     private final AtomicBoolean mRegisteredForSatelliteCapabilitiesChanged =
401             new AtomicBoolean(false);
402     private final AtomicBoolean mIsModemEnabledReportingNtnSignalStrength =
403             new AtomicBoolean(false);
404     private final AtomicBoolean mLatestRequestedStateForNtnSignalStrengthReport =
405             new AtomicBoolean(false);
406     private final AtomicBoolean mRegisteredForSatelliteSupportedStateChanged =
407             new AtomicBoolean(false);
408     private final AtomicBoolean mRegisteredForSatelliteRegistrationFailure =
409             new AtomicBoolean(false);
410     private final AtomicBoolean mRegisteredForTerrestrialNetworkAvailableChanged =
411             new AtomicBoolean(false);
412     private final AtomicBoolean mRegisteredForSatelliteCommunicationAccessStateChanged =
413         new AtomicBoolean(false);
414     /**
415      * Map key: subId, value: callback to get error code of the provision request.
416      */
417     private final ConcurrentHashMap<Integer, Consumer<Integer>> mSatelliteProvisionCallbacks =
418             new ConcurrentHashMap<>();
419 
420     /**
421      * Map key: binder of the callback, value: callback to receive provision state changed events.
422      */
423     private final ConcurrentHashMap<IBinder, ISatelliteProvisionStateCallback>
424             mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>();
425     /**
426      * Map key: binder of the callback, value: callback to receive non-terrestrial signal strength
427      * state changed events.
428      */
429     private final ConcurrentHashMap<IBinder, INtnSignalStrengthCallback>
430             mNtnSignalStrengthChangedListeners = new ConcurrentHashMap<>();
431     /**
432      * Map key: binder of the callback, value: callback to receive satellite capabilities changed
433      * events.
434      */
435     private final ConcurrentHashMap<IBinder, ISatelliteCapabilitiesCallback>
436             mSatelliteCapabilitiesChangedListeners = new ConcurrentHashMap<>();
437     /**
438      * Map key: binder of the callback, value: callback to receive supported state changed events.
439      */
440     private final ConcurrentHashMap<IBinder, IBooleanConsumer>
441             mSatelliteSupportedStateChangedListeners = new ConcurrentHashMap<>();
442 
443     /**
444      * Map key: binder of the callback, value: callback to satellite registration failure
445      */
446     private final ConcurrentHashMap<IBinder, ISatelliteModemStateCallback>
447             mSatelliteRegistrationFailureListeners = new ConcurrentHashMap<>();
448     /**
449      * Map key: binder of the callback, value: callback to receive terrestrial network
450      * available changed
451      */
452     private final ConcurrentHashMap<IBinder, ISatelliteModemStateCallback>
453             mTerrestrialNetworkAvailableChangedListeners = new ConcurrentHashMap<>();
454     /**
455      * Map key: binder of the callback, value: callback to receive selected NB IOT satellite
456      * subscription changed
457      */
458     private final ConcurrentHashMap<IBinder, ISelectedNbIotSatelliteSubscriptionCallback>
459             mSelectedNbIotSatelliteSubscriptionChangedListeners = new ConcurrentHashMap<>();
460 
461     protected final Object mIsSatelliteSupportedLock = new Object();
462     @GuardedBy("mIsSatelliteSupportedLock")
463     protected Boolean mIsSatelliteSupported = null;
464     private boolean mIsDemoModeEnabled = false;
465     private boolean mIsEmergency = false;
466     private final Object mIsSatelliteEnabledLock = new Object();
467     @GuardedBy("mIsSatelliteEnabledLock")
468     private Boolean mIsSatelliteEnabled = null;
469     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
470     protected final Object mIsRadioOnLock = new Object();
471     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
472     protected boolean mIsRadioOn;
473     @GuardedBy("mIsRadioOnLock")
474     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
475     protected boolean mRadioOffRequested = false;
476     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
477     protected final Object mDeviceProvisionLock = new Object();
478     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
479     @GuardedBy("mDeviceProvisionLock")
480     protected Boolean mIsDeviceProvisioned = null;
481     @GuardedBy("mDeviceProvisionLock")
482     private Boolean mOverriddenIsSatelliteViaOemProvisioned = null;
483     private final Object mSatelliteCapabilitiesLock = new Object();
484     @GuardedBy("mSatelliteCapabilitiesLock")
485     private SatelliteCapabilities mSatelliteCapabilities;
486     private final Object mNeedsSatellitePointingLock = new Object();
487     @GuardedBy("mNeedsSatellitePointingLock")
488     private boolean mNeedsSatellitePointing = false;
489     private final Object mNtnSignalsStrengthLock = new Object();
490     @GuardedBy("mNtnSignalsStrengthLock")
491     private NtnSignalStrength mNtnSignalStrength =
492             new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
493     /** Key: subId, value: (key: PLMN, value: set of
494      * {@link android.telephony.NetworkRegistrationInfo.ServiceType})
495      */
496     @GuardedBy("mSupportedSatelliteServicesLock")
497     @NonNull private final Map<Integer, Map<String, Set<Integer>>>
498             mSatelliteServicesSupportedByCarriersFromConfig = new HashMap<>();
499     @NonNull private final Object mSupportedSatelliteServicesLock = new Object();
500     @NonNull private final List<String> mSatellitePlmnListFromOverlayConfig;
501     @NonNull private final CarrierConfigManager mCarrierConfigManager;
502     @NonNull private final CarrierConfigManager.CarrierConfigChangeListener
503             mCarrierConfigChangeListener;
504     @NonNull private final ConfigProviderAdaptor.Callback mConfigDataUpdatedCallback;
505     @NonNull private final Object mCarrierConfigArrayLock = new Object();
506     @NonNull
507     private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener;
508     @GuardedBy("mCarrierConfigArrayLock")
509     @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>();
510     @GuardedBy("mIsSatelliteEnabledLock")
511     /** Key: Subscription ID, value: set of restriction reasons for satellite communication.*/
512     @NonNull private final Map<Integer, Set<Integer>> mSatelliteAttachRestrictionForCarrierArray =
513             new HashMap<>();
514     @GuardedBy("mIsSatelliteEnabledLock")
515     /** Key: Subscription ID, value: the actual satellite enabled state in the modem -
516      * {@code true} for enabled and {@code false} for disabled. */
517     @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub =
518             new HashMap<>();
519     /** Key: subId, value: (key: Regional satellite config Id string, value: Integer
520      * arrays of earfcns in the corresponding regions.)
521      */
522     @GuardedBy("mRegionalSatelliteEarfcnsLock")
523     @NonNull private final Map<Integer, Map<String, Set<Integer>>>
524             mRegionalSatelliteEarfcns = new HashMap<>();
525     @NonNull private final Object mRegionalSatelliteEarfcnsLock = new Object();
526     @NonNull private final FeatureFlags mFeatureFlags;
527     @NonNull private final Object mSatelliteConnectedLock = new Object();
528     /** Key: Subscription ID; Value: Last satellite connected time */
529     @GuardedBy("mSatelliteConnectedLock")
530     @NonNull private final SparseArray<Long> mLastSatelliteDisconnectedTimesMillis =
531             new SparseArray<>();
532     /**
533      * Key: Subscription ID; Value: {@code true} if satellite was just connected,
534      * {@code false} otherwise.
535      */
536     @GuardedBy("mSatelliteConnectedLock")
537     @NonNull private final SparseBooleanArray
538             mWasSatelliteConnectedViaCarrier = new SparseBooleanArray();
539 
540     @GuardedBy("mSatelliteConnectedLock")
541     @NonNull private final SparseBooleanArray mLastNotifiedNtnMode = new SparseBooleanArray();
542 
543     @GuardedBy("mSatelliteConnectedLock")
544     @NonNull private final SparseBooleanArray mInitialized = new SparseBooleanArray();
545 
546     /**
547      * Boolean set to {@code true} when device is eligible to connect to carrier roaming
548      * non-terrestrial network else set to {@code false}.
549      */
550     @GuardedBy("mSatellitePhoneLock")
551     private Boolean mLastNotifiedNtnEligibility = null;
552     @GuardedBy("mSatellitePhoneLock")
553     private boolean mCheckingAccessRestrictionInProgress = false;
554 
555     @GuardedBy("mSatelliteConnectedLock")
556     @NonNull private final Map<Integer, CarrierRoamingSatelliteSessionStats>
557             mCarrierRoamingSatelliteSessionStatsMap = new HashMap<>();
558 
559     /**
560      * Key: Subscription ID; Value: set of
561      * {@link android.telephony.NetworkRegistrationInfo.ServiceType}
562      */
563     @GuardedBy("mSatelliteConnectedLock")
564     @NonNull private final Map<Integer, List<Integer>>
565             mSatModeCapabilitiesForCarrierRoaming = new HashMap<>();
566 
567     @GuardedBy("mSatelliteConnectedLock")
568     private SparseArray<NtnSignalStrength> mLastNotifiedCarrierRoamingNtnSignalStrength =
569             new SparseArray<>();
570 
571     /**
572      * This is used for testing only. When mEnforcedEmergencyCallToSatelliteHandoverType is valid,
573      * Telephony will ignore the IMS registration status and cellular availability, and always send
574      * the connection event EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
575      */
576     private int mEnforcedEmergencyCallToSatelliteHandoverType =
577             INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
578     private int mDelayInSendingEventDisplayEmergencyMessage = 0;
579     @NonNull private SharedPreferences mSharedPreferences = null;
580 
581     @Nullable private PersistentLogger mPersistentLogger = null;
582 
583     /**
584      * Key : Subscription ID, Value: {@code true} if the EntitlementStatus is enabled,
585      * {@code false} otherwise.
586      */
587     @GuardedBy("mSupportedSatelliteServicesLock")
588     private SparseBooleanArray mSatelliteEntitlementStatusPerCarrier = new SparseBooleanArray();
589     /** Key Subscription ID, value : PLMN allowed list from entitlement. */
590     @GuardedBy("mSupportedSatelliteServicesLock")
591     private SparseArray<List<String>> mEntitlementPlmnListPerCarrier = new SparseArray<>();
592     /** Key Subscription ID, value : PLMN barred list from entitlement. */
593     @GuardedBy("mSupportedSatelliteServicesLock")
594     private SparseArray<List<String>> mEntitlementBarredPlmnListPerCarrier = new SparseArray<>();
595     /**
596      * Key : Subscription ID, Value : If there is an entitlementPlmnList, use it. Otherwise, use the
597      * carrierPlmnList. */
598     @GuardedBy("mSupportedSatelliteServicesLock")
599     private final SparseArray<List<String>> mMergedPlmnListPerCarrier = new SparseArray<>();
600     /** Key Subscription ID, value : map to plmn info with related data plan. */
601     @GuardedBy("mSupportedSatelliteServicesLock")
602     SparseArray<Map<String, Integer>> mEntitlementDataPlanMapPerCarrier = new SparseArray<>();
603     /** Key Subscription ID, value : map to plmn info with related service type. */
604     @GuardedBy("mSupportedSatelliteServicesLock")
605     SparseArray<Map<String, List<Integer>>> mEntitlementServiceTypeMapPerCarrier =
606             new SparseArray<>();
607     /** Key Subscription ID, value : map to plmn info with related service policy for data service */
608     @GuardedBy("mSupportedSatelliteServicesLock")
609     SparseArray<Map<String, Integer>> mEntitlementDataServicePolicyMapPerCarrier =
610             new SparseArray<>();
611     /** Key Subscription ID, value : map to plmn info with related service policy for voice service */
612     @GuardedBy("mSupportedSatelliteServicesLock")
613     SparseArray<Map<String, Integer>> mEntitlementVoiceServicePolicyMapPerCarrier =
614             new SparseArray<>();
615     private static AtomicLong sNextSatelliteEnableRequestId = new AtomicLong(0);
616     private static AtomicLong sNextSystemSelectionChannelsUpdateRequestId = new AtomicLong(0);
617     // key : subscriberId, value : provisioned or not.
618     @GuardedBy("mSatelliteTokenProvisionedLock")
619     private Map<String, Boolean> mProvisionedSubscriberId = new HashMap<>();
620     // key : subscriberId, value : subId
621     @GuardedBy("mSatelliteTokenProvisionedLock")
622     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
623     protected Map<String, Integer> mSubscriberIdPerSub = new HashMap<>();
624     // key : priority, low value is high, value : List<SubscriptionInfo>
625     @GuardedBy("mSatelliteTokenProvisionedLock")
626     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
627     protected TreeMap<Integer, List<SubscriptionInfo>> mSubsInfoListPerPriority = new TreeMap<>();
628     // List of subscriber information and status at the time of last evaluation
629     @GuardedBy("mSatelliteTokenProvisionedLock")
630     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
631     private List<SatelliteSubscriberProvisionStatus> mLastEvaluatedSubscriberProvisionStatus =
632             new ArrayList<>();
633     // The ID of the satellite subscription that has highest priority and is provisioned.
634     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
635     protected int mSelectedSatelliteSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
636     // The last ICC ID that framework configured to modem.
637     @GuardedBy("mSatelliteTokenProvisionedLock")
638     private String mLastConfiguredIccId;
639     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
640     @NonNull protected final Object mSatelliteTokenProvisionedLock = new Object();
641     private long mWaitTimeForSatelliteEnablingResponse;
642     private long mDemoPointingAlignedDurationMillis;
643     private long mDemoPointingNotAlignedDurationMillis;
644     private long mEvaluateEsosProfilesPrioritizationDurationMillis;
645     private final Object mLock = new Object();
646     @GuardedBy("mLock")
647     private long mLastEmergencyCallTime;
648     private long mSatelliteEmergencyModeDurationMillis;
649     private static final int DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS = 300;
650     private AlertDialog mNetworkSelectionModeAutoDialog = null;
651 
652     /** Key used to read/write satellite system notification done in shared preferences. */
653     private static final String SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY =
654             "satellite_system_notification_done_key";
655     private static final String SATELLITE_SYSTEM_NOTIFICATION_TIME =
656             "satellite_system_notification_time";
657     // The notification tag used when showing a notification. The combination of notification tag
658     // and notification id should be unique within the phone app.
659     private static final String NOTIFICATION_TAG = "SatelliteController";
660     private static final int NOTIFICATION_ID = 1;
661     private static final String NOTIFICATION_CHANNEL = "satelliteChannel";
662     private static final String NOTIFICATION_CHANNEL_ID = "satellite";
663 
664     private final RegistrantList mSatelliteConfigUpdateChangedRegistrants = new RegistrantList();
665     private final RegistrantList mSatelliteSubIdChangedRegistrants = new RegistrantList();
666     private final BTWifiNFCStateReceiver mBTWifiNFCSateReceiver;
667     private final UwbAdapterStateCallback mUwbAdapterStateCallback;
668     private final List<Integer> mCtsSatelliteAccessAllowedSubIds = new ArrayList<>();
669 
670     private long mSessionStartTimeStamp;
671     private long mSessionProcessingTimeStamp;
672 
673     // Variable for backup and restore device's screen rotation settings.
674     private String mDeviceRotationLockToBackupAndRestore = null;
675     // This is used for testing only. Context#getSystemService is a final API and cannot be
676     // mocked. Using this to inject a mock SubscriptionManager to work around this limitation.
677     private SubscriptionManager mInjectSubscriptionManager = null;
678 
679     private final Object mIsWifiConnectedLock = new Object();
680     @GuardedBy("mIsWifiConnectedLock")
681     private boolean mIsWifiConnected = false;
682     private boolean mHasSentBroadcast = false;
683     // For satellite CTS test which to configure intent component with the necessary values.
684     private boolean mChangeIntentComponent = false;
685     private String mConfigSatelliteGatewayServicePackage = "";
686     private String mConfigSatelliteCarrierRoamingEsosProvisionedClass = "";
687 
688     private boolean mIsNotificationShowing = false;
689     private static final String OPEN_MESSAGE_BUTTON = "open_message_button";
690     private static final String HOW_IT_WORKS_BUTTON = "how_it_works_button";
691     private static final String ACTION_NOTIFICATION_CLICK = "action_notification_click";
692     private static final String ACTION_NOTIFICATION_DISMISS = "action_notification_dismiss";
693     private AtomicBoolean mOverrideNtnEligibility;
694     private String mDefaultSmsPackageName = "";
695     private String mSatelliteGatewayServicePackageName = "";
696     private Boolean mOverriddenDisableSatelliteWhileEnableInProgressSupported = null;
697 
698     private final Object mNtnSmsSupportedByMessagesAppLock = new Object();
699     @GuardedBy("mNtnSmsSupportedByMessagesAppLock")
700     private Boolean mNtnSmsSupportedByMessagesApp = null;
701 
702     private final Object mCarrierRoamingNtnAllSatellitePlmnSetLock = new Object();
703     @GuardedBy("mCarrierRoamingNtnAllSatellitePlmnSetLock")
704     private Set<String> mCarrierRoamingNtnAllSatellitePlmnSet = null;
705 
706     private final Object mSatelliteModemStateLock = new Object();
707     @GuardedBy("mSatelliteModemStateLock")
708     @SatelliteManager.SatelliteModemState
709     private int mSatelliteModemState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN;
710 
711     // Data Plan types at entitlement for the plmn allowed
712     public static final int SATELLITE_DATA_PLAN_METERED = 0;
713     public static final int SATELLITE_DATA_PLAN_UNMETERED = 1;
714     @IntDef(prefix = {"SATELLITE_DATA_PLAN_"}, value = {
715             SATELLITE_DATA_PLAN_METERED,
716             SATELLITE_DATA_PLAN_UNMETERED,
717     })
718     @Retention(RetentionPolicy.SOURCE)
719     public @interface SatelliteDataPlan {}
720     private BroadcastReceiver
721             mDefaultSmsSubscriptionChangedBroadcastReceiver = new BroadcastReceiver() {
722                 @Override
723                 public void onReceive(Context context, Intent intent) {
724                     if (intent.getAction().equals(
725                             SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED)) {
726                         plogd("Default SMS subscription changed");
727                         sendRequestAsync(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION, null, null);
728                     }
729                 }
730             };
731 
732     private BroadcastReceiver mPackageStateChangedReceiver = new BroadcastReceiver() {
733         @Override
734         public void onReceive(Context context, Intent intent) {
735             mDefaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(mContext);
736             mSatelliteGatewayServicePackageName = getConfigSatelliteGatewayServicePackage();
737             String schemeSpecificPart = intent.getData().getSchemeSpecificPart();
738             plogd("packageStateChanged: " + intent.getData().toString()
739                     + " DefaultSmsPackageName:" + mDefaultSmsPackageName);
740 
741             if (!schemeSpecificPart.equals(mSatelliteGatewayServicePackageName)
742                     && !schemeSpecificPart.equals(mDefaultSmsPackageName)) {
743                 plogv("Neither SMS or SatelliteGateway package");
744                 return;
745             }
746             int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
747             if (activeSubIds != null) {
748                 for (int activeSubId : activeSubIds) {
749                     plogd("mPackageStateChangedReceiver: activeSubId= " + activeSubId);
750                     handleCarrierRoamingNtnAvailableServicesChanged(activeSubId);
751                 }
752             } else {
753                 ploge("mPackageStateChangedReceiver: activeSubIds is null");
754             }
755         }
756     };
757 
758     protected BroadcastReceiver mLocationServiceStateChangedReceiver = new BroadcastReceiver() {
759         @Override
760         public void onReceive(Context context, Intent intent) {
761             // Check whether user has turned on/off location manager from settings menu
762             if (intent.getAction().equals(LocationManager.MODE_CHANGED_ACTION)) {
763                 plogd("mLocationServiceStateChangedReceiver");
764                 sendRequestAsync(CMD_LOCATION_SERVICE_STATE_CHANGED, null, null);
765             }
766         }
767     };
768 
769     // List of device states returned from DeviceStateManager to determine if running on a foldable
770     // device.
771     private List<DeviceState> mDeviceStates = new ArrayList();
772 
773     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
774     protected final Object mSatelliteAccessConfigLock = new Object();
775     @GuardedBy("mSatelliteAccessConfigLock")
776     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
777     protected List<Integer> mCurrentLocationTagIds = new ArrayList();
778     @GuardedBy("mSatelliteAccessConfigLock")
779     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
780     protected boolean mSatelliteAccessAllowed = false;
781 
782     public static final int RESULT_RECEIVER_COUNT_ANOMALY_THRESHOLD = 500;
783     protected final Object mResultReceiverTotalCountLock = new Object();
784     @GuardedBy("mResultReceiverTotalCountLock")
785     protected int mResultReceiverTotalCount;
786     @GuardedBy("mResultReceiverTotalCountLock")
787     protected HashMap<String, Integer> mResultReceiverCountPerMethodMap = new HashMap<>();
788 
789     // Satellite anomaly uuid -- ResultReceiver count threshold exceeded
790     private final UUID mAnomalyUnexpectedResultReceiverCountUUID =
791             UUID.fromString("e268f22d-9bba-4d27-b76a-1c7f5b42e241");
792 
generateAnomalyUnexpectedResultReceiverCountUUID(int error, int errorCode)793     private UUID generateAnomalyUnexpectedResultReceiverCountUUID(int error, int errorCode) {
794         long lerror = error;
795         long lerrorCode = errorCode;
796         return new UUID(mAnomalyUnexpectedResultReceiverCountUUID.getMostSignificantBits(),
797                 mAnomalyUnexpectedResultReceiverCountUUID.getLeastSignificantBits()
798                         + ((lerrorCode << 32) + lerror));
799     }
800 
801     /**
802      * Increments the ResultReceiver count and logs the caller information.
803      * If the count exceeds the threshold, it reports an anomaly via AnomalyReporter.
804      *
805      * @param caller The caller information that created the ResultReceiver
806      *               (e.g., class name and method name)
807      */
incrementResultReceiverCount(String caller)808     public void incrementResultReceiverCount(String caller) {
809         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
810             synchronized (mResultReceiverTotalCountLock) {
811                 mResultReceiverTotalCount++;
812                 logd("[incrementResultReceiverCount] : " + caller
813                         + " | ResultReceiver total count= " + mResultReceiverTotalCount);
814                 mResultReceiverCountPerMethodMap.compute(caller,
815                         (k, v) -> v == null ? 1 : v + 1);
816 
817                 if (mResultReceiverTotalCount > RESULT_RECEIVER_COUNT_ANOMALY_THRESHOLD) {
818                     loge("[mResultReceiverTotalCount] is exceeds limits : "
819                             + mResultReceiverTotalCount);
820                     loge("[incrementResultReceiverCount] mResultReceiverCountPerMethodMap is "
821                             + mResultReceiverCountPerMethodMap);
822                     AnomalyReporter.reportAnomaly(
823                             generateAnomalyUnexpectedResultReceiverCountUUID(0, 0),
824                             "Satellite ResultReceiver total count= "
825                                     + mResultReceiverTotalCount + " exceeds limit.");
826                 }
827             }
828         } else {
829             logd("[incrementResultReceiverCount]: carrierRoamingNbIotNtn is not enabled");
830         }
831     }
832 
833     /**
834      * Decrements the ResultReceiver count and logs the caller information.
835      * Prevents the count from going below zero.
836      *
837      * @param caller The caller information that released the ResultReceiver
838      *               (e.g., class name and method name)
839      */
decrementResultReceiverCount(String caller)840     public void decrementResultReceiverCount(String caller) {
841         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
842             synchronized (mResultReceiverTotalCountLock) {
843                 if (mResultReceiverTotalCount > 0) {
844                     mResultReceiverTotalCount--;
845                 }
846                 logd("[decrementResultReceiverCount] : " + caller
847                         + " | ResultReceiver total count=" + mResultReceiverTotalCount);
848                 mResultReceiverCountPerMethodMap.computeIfPresent(caller,
849                         (k, v) -> v > 0 ? v - 1 : v);
850             }
851         } else {
852             logd("[decrementResultReceiverCount]: carrierRoamingNbIotNtn is not enabled");
853         }
854     }
855 
856     /**
857      * @return The singleton instance of SatelliteController.
858      */
getInstance()859     public static SatelliteController getInstance() {
860         if (sInstance == null) {
861             loge("SatelliteController was not yet initialized.");
862         }
863         return sInstance;
864     }
865 
866     /**
867      * Create the SatelliteController singleton instance.
868      * @param context The Context to use to create the SatelliteController.
869      * @param featureFlags The feature flag.
870      */
make(@onNull Context context, @NonNull FeatureFlags featureFlags)871     public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) {
872         if (sInstance == null) {
873             if (featureFlags.threadShred()) {
874                 sInstance = new SatelliteController(
875                         context, WorkerThread.get().getLooper(), featureFlags);
876             } else {
877                 HandlerThread satelliteThread = new HandlerThread(TAG);
878                 satelliteThread.start();
879                 sInstance = new SatelliteController(
880                         context, satelliteThread.getLooper(), featureFlags);
881             }
882         }
883     }
884 
885     /**
886      * Create a SatelliteController to act as a backend service of
887      * {@link android.telephony.satellite.SatelliteManager}
888      *
889      * @param context The Context for the SatelliteController.
890      * @param looper The looper for the handler. It does not run on main thread.
891      * @param featureFlags The feature flag.
892      */
893     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteController( @onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags)894     public SatelliteController(
895             @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) {
896         super(looper);
897 
898         mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context);
899         mContext = context;
900         mFeatureFlags = featureFlags;
901         Phone phone = SatelliteServiceUtils.getPhone();
902         synchronized (mSatellitePhoneLock) {
903             mSatellitePhone = phone;
904         }
905         mCi = phone.mCi;
906         mDSM = phone.getDeviceStateMonitor();
907         // Create the SatelliteModemInterface singleton, which is used to manage connections
908         // to the satellite service and HAL interface.
909         mSatelliteModemInterface = SatelliteModemInterface.make(
910                 mContext, this, mFeatureFlags);
911         mCountryDetector = TelephonyCountryDetector.getInstance(context, mFeatureFlags);
912         mCountryDetector.registerForWifiConnectivityStateChanged(this,
913                 EVENT_WIFI_CONNECTIVITY_STATE_CHANGED, null);
914         mTelecomManager = mContext.getSystemService(TelecomManager.class);
915 
916         // Create the PointingUIController singleton,
917         // which is used to manage interactions with PointingUI app.
918         mPointingAppController = PointingAppController.make(mContext, mFeatureFlags);
919 
920         // Create the SatelliteControllerMetrics to report controller metrics
921         // should be called before making DatagramController
922         mControllerMetricsStats = ControllerMetricsStats.make(mContext);
923         mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance();
924         mSessionMetricsStats = SessionMetricsStats.getInstance();
925         mCarrierRoamingSatelliteControllerStats =
926                 CarrierRoamingSatelliteControllerStats.getOrCreateInstance();
927         mSubscriptionManagerService = SubscriptionManagerService.getInstance();
928 
929         // Create the DatagramController singleton,
930         // which is used to send and receive satellite datagrams.
931         mDatagramController = DatagramController.make(
932                 mContext, looper, mFeatureFlags, mPointingAppController);
933 
934         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
935         synchronized (mIsRadioOnLock) {
936             mIsRadioOn = phone.isRadioOn();
937         }
938 
939         registerForPendingDatagramCount();
940         registerForSatelliteModemStateChanged();
941         registerForServiceStateChanged();
942         registerForSignalStrengthChanged();
943         registerForSatelliteCommunicationAccessStateChanged();
944         mContentResolver = mContext.getContentResolver();
945         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
946 
947         mBTWifiNFCSateReceiver = new BTWifiNFCStateReceiver();
948         mUwbAdapterStateCallback = new UwbAdapterStateCallback();
949         initializeSatelliteModeRadios();
950 
951         ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) {
952             @Override
953             public void onChange(boolean selfChange) {
954                 initializeSatelliteModeRadios();
955             }
956         };
957         if (mContentResolver != null) {
958             mContentResolver.registerContentObserver(
959                     Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS),
960                     false, satelliteModeRadiosContentObserver);
961         }
962 
963         mSatellitePlmnListFromOverlayConfig = readSatellitePlmnsFromOverlayConfig();
964         registerApplicationStateChanged();
965         registerLocationServiceStateChanged();
966         updateSupportedSatelliteServicesForActiveSubscriptions();
967         mCarrierConfigChangeListener =
968                 (slotIndex, subId, carrierId, specificCarrierId) ->
969                         handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
970         if (mCarrierConfigManager != null) {
971             mCarrierConfigManager.registerCarrierConfigChangeListener(
972                     new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
973         }
974 
975         mConfigDataUpdatedCallback = new ConfigProviderAdaptor.Callback() {
976             @Override
977             public void onChanged(@Nullable ConfigParser config) {
978                 SatelliteControllerHandlerRequest request =
979                         new SatelliteControllerHandlerRequest(true,
980                                 SatelliteServiceUtils.getPhone());
981                 sendRequestAsync(EVENT_SATELLITE_CONFIG_DATA_UPDATED, request, null);
982             }
983         };
984         TelephonyConfigUpdateInstallReceiver.getInstance()
985                 .registerCallback(Executors.newSingleThreadExecutor(), mConfigDataUpdatedCallback);
986 
987         mDSM.registerForSignalStrengthReportDecision(this, CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING,
988                 null);
989 
990         loadSatelliteSharedPreferences();
991         if (mSharedPreferences != null) {
992             try {
993                 synchronized (mNtnSmsSupportedByMessagesAppLock) {
994                     mNtnSmsSupportedByMessagesApp = mSharedPreferences.getBoolean(
995                             NTN_SMS_SUPPORTED_BY_MESSAGES_APP_KEY, false);
996                 }
997 
998                 synchronized (mCarrierRoamingNtnAllSatellitePlmnSetLock) {
999                     mCarrierRoamingNtnAllSatellitePlmnSet = mSharedPreferences.getStringSet(
1000                             CARRIER_ROAMING_NTN_ALL_SATELLITE_PLMN_SET_KEY, new HashSet<>());
1001                 }
1002             } catch (Exception ex) {
1003                 plogd("SatelliteController constructor: "
1004                         + "cannot get default shared preferences. e" + ex);
1005             }
1006         }
1007 
1008         mWaitTimeForSatelliteEnablingResponse = getWaitForSatelliteEnablingResponseTimeoutMillis();
1009         mDemoPointingAlignedDurationMillis = getDemoPointingAlignedDurationMillisFromResources();
1010         mDemoPointingNotAlignedDurationMillis =
1011                 getDemoPointingNotAlignedDurationMillisFromResources();
1012         mSatelliteEmergencyModeDurationMillis =
1013                 getSatelliteEmergencyModeDurationFromOverlayConfig(context);
1014         mEvaluateEsosProfilesPrioritizationDurationMillis =
1015                 getEvaluateEsosProfilesPrioritizationDurationMillis();
1016         sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
1017                 mEvaluateEsosProfilesPrioritizationDurationMillis);
1018 
1019         SubscriptionManager subscriptionManager = mContext.getSystemService(
1020                 SubscriptionManager.class);
1021         mSubscriptionsChangedListener = new SatelliteSubscriptionsChangedListener();
1022         if (subscriptionManager != null) {
1023             subscriptionManager.addOnSubscriptionsChangedListener(
1024                     new HandlerExecutor(new Handler(looper)), mSubscriptionsChangedListener);
1025         }
1026         registerDefaultSmsSubscriptionChangedBroadcastReceiver();
1027         updateSatelliteProvisionedStatePerSubscriberId();
1028         if (android.hardware.devicestate.feature.flags.Flags.deviceStatePropertyMigration()) {
1029             mDeviceStates = getSupportedDeviceStates();
1030         }
1031 
1032         mSatelliteOptimizedApplicationsTracker = new SatelliteOptimizedApplicationsTracker(
1033                 getLooper(), mContext
1034         );
1035 
1036         for (Phone phoneToSendRequest : PhoneFactory.getPhones()) {
1037             sendRequestAsync(CMD_GET_SATELLITE_ENABLED_FOR_CARRIER, null, phoneToSendRequest);
1038         }
1039 
1040         logd("Satellite Tracker is created");
1041     }
1042 
1043     class SatelliteSubscriptionsChangedListener
1044             extends SubscriptionManager.OnSubscriptionsChangedListener {
1045 
1046         /**
1047          * Callback invoked when there is any change to any SubscriptionInfo.
1048          */
1049         @Override
onSubscriptionsChanged()1050         public void onSubscriptionsChanged() {
1051             handleSubscriptionsChanged();
1052         }
1053     }
1054 
1055     /**
1056      * Register a callback to get a updated satellite config data.
1057      * @param h Handler to notify
1058      * @param what msg.what when the message is delivered
1059      * @param obj AsyncResult.userObj when the message is delivered
1060      */
registerForConfigUpdateChanged(Handler h, int what, Object obj)1061     public void registerForConfigUpdateChanged(Handler h, int what, Object obj) {
1062         Registrant r = new Registrant(h, what, obj);
1063         mSatelliteConfigUpdateChangedRegistrants.add(r);
1064     }
1065 
1066     /**
1067      * Unregister a callback to get a updated satellite config data.
1068      * @param h Handler to notify
1069      */
unregisterForConfigUpdateChanged(Handler h)1070     public void unregisterForConfigUpdateChanged(Handler h) {
1071         mSatelliteConfigUpdateChangedRegistrants.remove(h);
1072     }
1073 
1074     /**
1075      * Register a callback to change the satelliteSubId.
1076      * @param h Handler to notify
1077      * @param what msg.what when the message is delivered
1078      * @param obj AsyncResult.userObj when the message is delivered
1079      */
registerForSatelliteSubIdChanged(Handler h, int what, Object obj)1080     public void registerForSatelliteSubIdChanged(Handler h, int what, Object obj) {
1081         Registrant r = new Registrant(h, what, obj);
1082         mSatelliteSubIdChangedRegistrants.add(r);
1083     }
1084 
1085     /**
1086      * Unregister a callback to get a updated satellite config data.
1087      * @param h Handler to notify
1088      */
unregisterForSatelliteSubIdChanged(Handler h)1089     public void unregisterForSatelliteSubIdChanged(Handler h) {
1090         mSatelliteSubIdChangedRegistrants.remove(h);
1091     }
1092     /**
1093      * Get satelliteConfig from SatelliteConfigParser
1094      */
getSatelliteConfig()1095     public SatelliteConfig getSatelliteConfig() {
1096         SatelliteConfigParser satelliteConfigParser = getSatelliteConfigParser();
1097         if (satelliteConfigParser == null) {
1098             Log.d(TAG, "satelliteConfigParser is not ready");
1099             return null;
1100         }
1101         return satelliteConfigParser.getConfig();
1102     }
1103 
1104     /**
1105      * This API should be used by only CTS/unit tests to reset the telephony configs set through
1106      * config updater
1107      */
1108     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
cleanUpTelephonyConfigs()1109     public void cleanUpTelephonyConfigs() {
1110         TelephonyConfigUpdateInstallReceiver.getInstance().cleanUpTelephonyConfigs();
1111     }
1112 
1113     /**
1114      * Get SatelliteConfigParser from TelephonyConfigUpdateInstallReceiver
1115      */
1116     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getSatelliteConfigParser()1117     public SatelliteConfigParser getSatelliteConfigParser() {
1118         return (SatelliteConfigParser) TelephonyConfigUpdateInstallReceiver
1119                 .getInstance().getConfigParser(DOMAIN_SATELLITE);
1120     }
1121 
1122     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
initializeSatelliteModeRadios()1123     protected void initializeSatelliteModeRadios() {
1124         if (mContentResolver != null) {
1125             IntentFilter radioStateIntentFilter = new IntentFilter();
1126 
1127             synchronized (mRadioStateLock) {
1128                 // Initialize radio states to default value
1129                 mDisableBTOnSatelliteEnabled = false;
1130                 mDisableNFCOnSatelliteEnabled = false;
1131                 mDisableWifiOnSatelliteEnabled = false;
1132                 mDisableUWBOnSatelliteEnabled = false;
1133 
1134                 mBTStateEnabled = false;
1135                 mNfcStateEnabled = false;
1136                 mWifiStateEnabled = false;
1137                 mUwbStateEnabled = false;
1138 
1139                 // Read satellite mode radios from settings
1140                 String satelliteModeRadios = Settings.Global.getString(mContentResolver,
1141                         Settings.Global.SATELLITE_MODE_RADIOS);
1142                 if (satelliteModeRadios == null) {
1143                     ploge("initializeSatelliteModeRadios: satelliteModeRadios is null");
1144                     return;
1145                 }
1146                 plogd("Radios To be checked when satellite is on: " + satelliteModeRadios);
1147 
1148                 if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) {
1149                     BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
1150                     if (bluetoothAdapter != null) {
1151                         mDisableBTOnSatelliteEnabled = true;
1152                         mBTStateEnabled = bluetoothAdapter.isEnabled();
1153                         radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
1154                     }
1155                 }
1156 
1157                 if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC)) {
1158                     Context applicationContext = mContext.getApplicationContext();
1159                     NfcAdapter nfcAdapter = null;
1160                     if (applicationContext != null) {
1161                         nfcAdapter = NfcAdapter.getDefaultAdapter(mContext.getApplicationContext());
1162                     }
1163                     if (nfcAdapter != null) {
1164                         mDisableNFCOnSatelliteEnabled = true;
1165                         mNfcStateEnabled = nfcAdapter.isEnabled();
1166                         radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
1167                     }
1168                 }
1169 
1170                 if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI)) {
1171                     WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
1172                     if (wifiManager != null) {
1173                         mDisableWifiOnSatelliteEnabled = true;
1174                         mWifiStateEnabled = wifiManager.isWifiEnabled();
1175                         radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
1176                     }
1177                 }
1178 
1179                 try {
1180                     // Unregister receiver before registering it.
1181                     mContext.unregisterReceiver(mBTWifiNFCSateReceiver);
1182                 } catch (IllegalArgumentException e) {
1183                     plogd("initializeSatelliteModeRadios: unregisterReceiver, e=" + e);
1184                 }
1185                 mContext.registerReceiver(mBTWifiNFCSateReceiver, radioStateIntentFilter);
1186 
1187                 if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB)) {
1188                     UwbManager uwbManager = mContext.getSystemService(UwbManager.class);
1189                     if (uwbManager != null) {
1190                         mDisableUWBOnSatelliteEnabled = true;
1191                         mUwbStateEnabled = uwbManager.isUwbEnabled();
1192                         final long identity = Binder.clearCallingIdentity();
1193                         try {
1194                             // Unregister callback before registering it.
1195                             uwbManager.unregisterAdapterStateCallback(mUwbAdapterStateCallback);
1196                             uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(),
1197                                     mUwbAdapterStateCallback);
1198                         } finally {
1199                             Binder.restoreCallingIdentity(identity);
1200                         }
1201                     }
1202                 }
1203 
1204                 plogd("mDisableBTOnSatelliteEnabled: " + mDisableBTOnSatelliteEnabled
1205                         + " mDisableNFCOnSatelliteEnabled: " + mDisableNFCOnSatelliteEnabled
1206                         + " mDisableWifiOnSatelliteEnabled: " + mDisableWifiOnSatelliteEnabled
1207                         + " mDisableUWBOnSatelliteEnabled: " + mDisableUWBOnSatelliteEnabled);
1208 
1209                 plogd("mBTStateEnabled: " + mBTStateEnabled
1210                         + " mNfcStateEnabled: " + mNfcStateEnabled
1211                         + " mWifiStateEnabled: " + mWifiStateEnabled
1212                         + " mUwbStateEnabled: " + mUwbStateEnabled);
1213             }
1214         }
1215     }
1216 
1217     protected class UwbAdapterStateCallback implements UwbManager.AdapterStateCallback {
1218 
toString(int state)1219         public String toString(int state) {
1220             switch (state) {
1221                 case UwbManager.AdapterStateCallback.STATE_DISABLED:
1222                     return "Disabled";
1223 
1224                 case UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE:
1225                     return "Inactive";
1226 
1227                 case UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE:
1228                     return "Active";
1229 
1230                 default:
1231                     return "";
1232             }
1233         }
1234 
1235         @Override
onStateChanged(int state, int reason)1236         public void onStateChanged(int state, int reason) {
1237             plogd("UwbAdapterStateCallback#onStateChanged() called, state = " + toString(state));
1238             plogd("Adapter state changed reason " + String.valueOf(reason));
1239             if (state == UwbManager.AdapterStateCallback.STATE_DISABLED) {
1240                 setUwbEnabledState(false);
1241                 evaluateToSendSatelliteEnabledSuccess();
1242             } else {
1243                 setUwbEnabledState(true);
1244             }
1245             plogd("mUwbStateEnabled: " + getUwbEnabledState());
1246         }
1247     }
1248 
1249     protected class BTWifiNFCStateReceiver extends BroadcastReceiver {
1250         @Override
onReceive(Context context, Intent intent)1251         public void onReceive(Context context, Intent intent) {
1252             final String action = intent.getAction();
1253             if (action == null) {
1254                 plogd("BTWifiNFCStateReceiver NULL action for intent " + intent);
1255                 return;
1256             }
1257 
1258             switch (action) {
1259                 case BluetoothAdapter.ACTION_STATE_CHANGED:
1260                     int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
1261                             BluetoothAdapter.ERROR);
1262                     boolean currentBTStateEnabled = getBTEnabledState();
1263                     if (btState == BluetoothAdapter.STATE_OFF) {
1264                         setBTEnabledState(false);
1265                         evaluateToSendSatelliteEnabledSuccess();
1266                     } else if (btState == BluetoothAdapter.STATE_ON) {
1267                         setBTEnabledState(true);
1268                     }
1269 
1270                     if (currentBTStateEnabled != getBTEnabledState()) {
1271                         plogd("mBTStateEnabled=" + getBTEnabledState());
1272                     }
1273                     break;
1274 
1275                 case NfcAdapter.ACTION_ADAPTER_STATE_CHANGED:
1276                     int nfcState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1);
1277                     boolean currentNfcStateEnabled = getNfcEnabledState();
1278                     if (nfcState == NfcAdapter.STATE_ON) {
1279                         setNfcEnabledState(true);
1280                     } else if (nfcState == NfcAdapter.STATE_OFF) {
1281                         setNfcEnabledState(false);
1282                         evaluateToSendSatelliteEnabledSuccess();
1283                     }
1284 
1285                     if (currentNfcStateEnabled != getNfcEnabledState()) {
1286                         plogd("mNfcStateEnabled=" + getNfcEnabledState());
1287                     }
1288                     break;
1289 
1290                 case WifiManager.WIFI_STATE_CHANGED_ACTION:
1291                     int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1292                             WifiManager.WIFI_STATE_UNKNOWN);
1293                     boolean currentWifiStateEnabled = getWifiEnabledState();
1294                     if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
1295                         setWifiEnabledState(true);
1296                     } else if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
1297                         setWifiEnabledState(false);
1298                         evaluateToSendSatelliteEnabledSuccess();
1299                     }
1300 
1301                     if (currentWifiStateEnabled != getWifiEnabledState()) {
1302                         plogd("mWifiStateEnabled=" + getWifiEnabledState());
1303                     }
1304                     break;
1305                 default:
1306                     break;
1307             }
1308         }
1309     }
1310 
1311     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1312     public static final class SatelliteControllerHandlerRequest {
1313         /** The argument to use for the request */
1314         public @NonNull Object argument;
1315         /** The caller needs to specify the phone to be used for the request */
1316         public @NonNull Phone phone;
1317         /** The result of the request that is run on the main thread */
1318         public @Nullable Object result;
1319 
SatelliteControllerHandlerRequest(Object argument, Phone phone)1320         public SatelliteControllerHandlerRequest(Object argument, Phone phone) {
1321             this.argument = argument;
1322             this.phone = phone;
1323         }
1324     }
1325 
1326     private static final class RequestSatelliteEnabledArgument {
1327         public boolean enableSatellite;
1328         public boolean enableDemoMode;
1329         public boolean isEmergency;
1330         @NonNull public Consumer<Integer> callback;
1331         public long requestId;
1332 
RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, Consumer<Integer> callback)1333         RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode,
1334                 boolean isEmergency, Consumer<Integer> callback) {
1335             this.enableSatellite = enableSatellite;
1336             this.enableDemoMode = enableDemoMode;
1337             this.isEmergency = isEmergency;
1338             this.callback = callback;
1339             this.requestId = sNextSatelliteEnableRequestId.getAndUpdate(
1340                     n -> ((n + 1) % Long.MAX_VALUE));
1341         }
1342     }
1343 
1344     private static final class RequestHandleSatelliteAttachRestrictionForCarrierArgument {
1345         public int subId;
1346         @SatelliteManager.SatelliteCommunicationRestrictionReason
1347         public int reason;
1348         @NonNull public Consumer<Integer> callback;
1349 
RequestHandleSatelliteAttachRestrictionForCarrierArgument(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, Consumer<Integer> callback)1350         RequestHandleSatelliteAttachRestrictionForCarrierArgument(int subId,
1351                 @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
1352                 Consumer<Integer> callback) {
1353             this.subId = subId;
1354             this.reason = reason;
1355             this.callback = callback;
1356         }
1357     }
1358 
1359     private static final class ProvisionSatelliteServiceArgument {
1360         @NonNull public String token;
1361         @NonNull public byte[] provisionData;
1362         @NonNull public Consumer<Integer> callback;
1363         public int subId;
1364 
ProvisionSatelliteServiceArgument(String token, byte[] provisionData, Consumer<Integer> callback, int subId)1365         ProvisionSatelliteServiceArgument(String token, byte[] provisionData,
1366                 Consumer<Integer> callback, int subId) {
1367             this.token = token;
1368             this.provisionData = provisionData;
1369             this.callback = callback;
1370             this.subId = subId;
1371         }
1372     }
1373 
1374     private static final class UpdateSystemSelectionChannelsArgument {
1375         public @NonNull List<SystemSelectionSpecifier> systemSelectionSpecifiers;
1376         public @NonNull ResultReceiver result;
1377         public long requestId;
1378 
UpdateSystemSelectionChannelsArgument( @onNull List<SystemSelectionSpecifier> systemSelectionSpecifiers, @NonNull ResultReceiver result)1379         UpdateSystemSelectionChannelsArgument(
1380                 @NonNull List<SystemSelectionSpecifier> systemSelectionSpecifiers,
1381                 @NonNull ResultReceiver result) {
1382             this.systemSelectionSpecifiers = systemSelectionSpecifiers;
1383             this.result = result;
1384             this.requestId = sNextSystemSelectionChannelsUpdateRequestId.getAndUpdate(
1385                     n -> ((n + 1) % Long.MAX_VALUE));
1386         }
1387     }
1388 
1389     /**
1390      * Arguments to send to SatelliteTransmissionUpdate registrants
1391      */
1392     public static final class SatelliteTransmissionUpdateArgument {
1393         @NonNull public Consumer<Integer> errorCallback;
1394         @NonNull public ISatelliteTransmissionUpdateCallback callback;
1395         public int subId;
1396 
SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback, ISatelliteTransmissionUpdateCallback callback, int subId)1397         SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback,
1398                 ISatelliteTransmissionUpdateCallback callback, int subId) {
1399             this.errorCallback = errorCallback;
1400             this.callback = callback;
1401             this.subId = subId;
1402         }
1403     }
1404 
1405     @Override
handleMessage(Message msg)1406     public void handleMessage(Message msg) {
1407         SatelliteControllerHandlerRequest request;
1408         Message onCompleted;
1409         AsyncResult ar;
1410 
1411         switch(msg.what) {
1412             case CMD_START_SATELLITE_TRANSMISSION_UPDATES: {
1413                 request = (SatelliteControllerHandlerRequest) msg.obj;
1414                 onCompleted =
1415                         obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
1416                 mPointingAppController.startSatelliteTransmissionUpdates(onCompleted);
1417                 break;
1418             }
1419 
1420             case EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE: {
1421                 handleStartSatelliteTransmissionUpdatesDone((AsyncResult) msg.obj);
1422                 break;
1423             }
1424 
1425             case CMD_STOP_SATELLITE_TRANSMISSION_UPDATES: {
1426                 request = (SatelliteControllerHandlerRequest) msg.obj;
1427                 onCompleted =
1428                         obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
1429                 mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted);
1430                 break;
1431             }
1432 
1433             case EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE: {
1434                 ar = (AsyncResult) msg.obj;
1435                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1436                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1437                         "stopSatelliteTransmissionUpdates");
1438                 ((Consumer<Integer>) request.argument).accept(error);
1439                 break;
1440             }
1441 
1442             case CMD_PROVISION_SATELLITE_SERVICE: {
1443                 request = (SatelliteControllerHandlerRequest) msg.obj;
1444                 ProvisionSatelliteServiceArgument argument =
1445                         (ProvisionSatelliteServiceArgument) request.argument;
1446                 if (mSatelliteProvisionCallbacks.containsKey(argument.subId)) {
1447                     argument.callback.accept(
1448                             SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS);
1449                     notifyRequester(request);
1450                     break;
1451                 }
1452                 mSatelliteProvisionCallbacks.put(argument.subId, argument.callback);
1453                 // Log the current time for provision triggered
1454                 mProvisionMetricsStats.setProvisioningStartTime();
1455                 Message provisionSatelliteServiceDoneEvent = this.obtainMessage(
1456                         EVENT_PROVISION_SATELLITE_SERVICE_DONE,
1457                         new AsyncResult(request, SATELLITE_RESULT_SUCCESS, null));
1458                 provisionSatelliteServiceDoneEvent.sendToTarget();
1459                 break;
1460             }
1461 
1462             case EVENT_PROVISION_SATELLITE_SERVICE_DONE: {
1463                 ar = (AsyncResult) msg.obj;
1464                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1465                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
1466                         "provisionSatelliteService");
1467                 handleEventProvisionSatelliteServiceDone(
1468                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
1469                 notifyRequester(request);
1470                 break;
1471             }
1472 
1473             case CMD_DEPROVISION_SATELLITE_SERVICE: {
1474                 request = (SatelliteControllerHandlerRequest) msg.obj;
1475                 ProvisionSatelliteServiceArgument argument =
1476                         (ProvisionSatelliteServiceArgument) request.argument;
1477                 if (argument.callback != null) {
1478                     mProvisionMetricsStats.setProvisioningStartTime();
1479                 }
1480                 Message deprovisionSatelliteServiceDoneEvent = this.obtainMessage(
1481                         EVENT_DEPROVISION_SATELLITE_SERVICE_DONE,
1482                         new AsyncResult(request, SATELLITE_RESULT_SUCCESS, null));
1483                 deprovisionSatelliteServiceDoneEvent.sendToTarget();
1484                 break;
1485             }
1486 
1487             case EVENT_DEPROVISION_SATELLITE_SERVICE_DONE: {
1488                 ar = (AsyncResult) msg.obj;
1489                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1490                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
1491                         "deprovisionSatelliteService");
1492                 handleEventDeprovisionSatelliteServiceDone(
1493                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
1494                 break;
1495             }
1496 
1497             case CMD_SET_SATELLITE_ENABLED: {
1498                 request = (SatelliteControllerHandlerRequest) msg.obj;
1499                 handleSatelliteEnabled(request);
1500                 break;
1501             }
1502 
1503             case EVENT_SET_SATELLITE_ENABLED_DONE: {
1504                 ar = (AsyncResult) msg.obj;
1505                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1506                 RequestSatelliteEnabledArgument argument =
1507                         (RequestSatelliteEnabledArgument) request.argument;
1508                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled");
1509                 plogd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error);
1510 
1511                 /*
1512                  * The timer to wait for EVENT_SET_SATELLITE_ENABLED_DONE might have expired and
1513                  * thus the request resources might have been cleaned up.
1514                  */
1515                 if (!shouldProcessEventSetSatelliteEnabledDone(argument)) {
1516                     plogw("The request ID=" + argument.requestId + ", enableSatellite="
1517                             + argument.enableSatellite + " was already processed");
1518                     return;
1519                 }
1520                 if (shouldStopWaitForEnableResponseTimer(argument)) {
1521                     stopWaitForSatelliteEnablingResponseTimer(argument);
1522                 } else {
1523                     plogd("Still waiting for the OFF state from modem");
1524                 }
1525 
1526                 if (error == SATELLITE_RESULT_SUCCESS) {
1527                     if (argument.enableSatellite) {
1528                         synchronized (mSatelliteEnabledRequestLock) {
1529                             mWaitingForRadioDisabled = true;
1530                             setDemoModeEnabled(argument.enableDemoMode);
1531                         }
1532                         // TODO (b/361139260): Start a timer to wait for other radios off
1533                         setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_TRUE);
1534                         setSettingsKeyToAllowDeviceRotation(SATELLITE_MODE_ENABLED_TRUE);
1535                         evaluateToSendSatelliteEnabledSuccess();
1536                     } else {
1537                         // Unregister importance listener for PointingUI when satellite is disabled
1538                         if (mNeedsSatellitePointing) {
1539                             mPointingAppController.removeListenerForPointingUI();
1540                         }
1541 
1542                         if (!isWaitingForSatelliteModemOff()) {
1543                             moveSatelliteToOffStateAndCleanUpResources(SATELLITE_RESULT_SUCCESS);
1544                         }
1545 
1546                         synchronized (mSatelliteEnabledRequestLock) {
1547                             mWaitingForDisableSatelliteModemResponse = false;
1548                         }
1549                     }
1550                     // Request NTN signal strength report when satellite enabled or disabled done.
1551                     mLatestRequestedStateForNtnSignalStrengthReport.set(argument.enableSatellite);
1552                     updateNtnSignalStrengthReporting(argument.enableSatellite);
1553                 } else {
1554                     if (argument.enableSatellite) {
1555                         /* Framework need to abort the enable attributes update request if any since
1556                          * modem failed to enable satellite.
1557                          */
1558                         abortSatelliteEnableAttributesUpdateRequest(
1559                                 SATELLITE_RESULT_REQUEST_ABORTED);
1560                         resetSatelliteEnabledRequest();
1561                     } else {
1562                         resetSatelliteDisabledRequest();
1563                     }
1564                     notifyEnablementFailedToSatelliteSessionController(argument.enableSatellite);
1565                     // If Satellite enable/disable request returned Error, no need to wait for radio
1566                     argument.callback.accept(error);
1567                 }
1568                 if (argument.enableSatellite) {
1569                     mSessionMetricsStats.resetSessionStatsShadowCounters();
1570                     mSessionMetricsStats.setInitializationResult(error)
1571                             .setSatelliteTechnology(getSupportedNtnRadioTechnology())
1572                             .setInitializationProcessingTime(
1573                                     getElapsedRealtime() - mSessionProcessingTimeStamp)
1574                             .setIsDemoMode(mIsDemoModeEnabled)
1575                             .setCarrierId(getSatelliteCarrierId())
1576                             .setIsEmergency(argument.isEmergency);
1577                     mSessionProcessingTimeStamp = 0;
1578 
1579                     if (error == SATELLITE_RESULT_SUCCESS) {
1580                         mControllerMetricsStats.onSatelliteEnabled();
1581                         mControllerMetricsStats.reportServiceEnablementSuccessCount();
1582                     } else {
1583                         mSessionMetricsStats.reportSessionMetrics();
1584                         mSessionStartTimeStamp = 0;
1585                         mControllerMetricsStats.reportServiceEnablementFailCount();
1586                     }
1587                 } else {
1588                     mSessionMetricsStats.setTerminationResult(error)
1589                             .setTerminationProcessingTime(getElapsedRealtime()
1590                                     - mSessionProcessingTimeStamp)
1591                             .setSessionDurationSec(calculateSessionDurationTimeSec())
1592                             .reportSessionMetrics();
1593                     mSessionStartTimeStamp = 0;
1594                     mSessionProcessingTimeStamp = 0;
1595                     mControllerMetricsStats.onSatelliteDisabled();
1596                     handlePersistentLoggingOnSessionEnd(mIsEmergency);
1597                     synchronized (mSatelliteEnabledRequestLock) {
1598                         mWaitingForDisableSatelliteModemResponse = false;
1599                     }
1600                 }
1601                 break;
1602             }
1603 
1604             case EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT: {
1605                 handleEventWaitForSatelliteEnablingResponseTimedOut(
1606                         (RequestSatelliteEnabledArgument) msg.obj);
1607                 break;
1608             }
1609 
1610             case CMD_UPDATE_SATELLITE_ENABLE_ATTRIBUTES: {
1611                 request = (SatelliteControllerHandlerRequest) msg.obj;
1612                 RequestSatelliteEnabledArgument argument =
1613                         (RequestSatelliteEnabledArgument) request.argument;
1614 
1615                 if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
1616                     plogd("UpdateEnableAttributes: carrierRoamingNbIotNtn flag is disabled");
1617                     sendErrorAndReportSessionMetrics(
1618                             SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS, argument.callback);
1619                     synchronized (mSatelliteEnabledRequestLock) {
1620                         mSatelliteEnableAttributesUpdateRequest = null;
1621                     }
1622                     break;
1623                 }
1624 
1625                 synchronized (mSatelliteEnabledRequestLock) {
1626                     if (mSatelliteEnabledRequest != null) {
1627                         plogd("UpdateEnableAttributes: Satellite is being enabled. Need to "
1628                                 + "wait until enable complete before updating attributes");
1629                         break;
1630                     }
1631                     if (isSatelliteBeingDisabled()) {
1632                         plogd("UpdateEnableAttributes: Satellite is being disabled. Aborting the "
1633                                 + "enable attributes update request");
1634                         mSatelliteEnableAttributesUpdateRequest = null;
1635                         argument.callback.accept(SATELLITE_RESULT_REQUEST_ABORTED);
1636                         break;
1637                     }
1638                 }
1639                 onCompleted = obtainMessage(EVENT_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_DONE, request);
1640                 SatelliteModemEnableRequestAttributes enableRequestAttributes =
1641                     createModemEnableRequest(argument);
1642                 if (enableRequestAttributes == null) {
1643                     plogw("UpdateEnableAttributes: enableRequestAttributes is null");
1644                     sendErrorAndReportSessionMetrics(
1645                         SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
1646                         argument.callback);
1647                     synchronized (mSatelliteEnabledRequestLock) {
1648                         mSatelliteEnableAttributesUpdateRequest = null;
1649                     }
1650                     break;
1651                 }
1652                 mSatelliteModemInterface.requestSatelliteEnabled(
1653                         enableRequestAttributes, onCompleted);
1654                 startWaitForUpdateSatelliteEnableAttributesResponseTimer(argument);
1655                 break;
1656             }
1657 
1658             case EVENT_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_DONE: {
1659                 ar = (AsyncResult) msg.obj;
1660                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1661                 RequestSatelliteEnabledArgument argument =
1662                         (RequestSatelliteEnabledArgument) request.argument;
1663                 int error =  SatelliteServiceUtils.getSatelliteError(
1664                         ar, "updateSatelliteEnableAttributes");
1665                 plogd("EVENT_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_DONE = " + error);
1666 
1667                 /*
1668                  * The timer to wait for EVENT_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_DONE might have
1669                  * expired and thus the request resources might have been cleaned up.
1670                  */
1671                 if (!shouldProcessEventUpdateSatelliteEnableAttributesDone(argument)) {
1672                     plogw("The update request ID=" + argument.requestId + " was already processed");
1673                     return;
1674                 }
1675                 stopWaitForUpdateSatelliteEnableAttributesResponseTimer(argument);
1676 
1677                 if (error == SATELLITE_RESULT_SUCCESS) {
1678                     setDemoModeEnabled(argument.enableDemoMode);
1679                     setEmergencyMode(argument.isEmergency);
1680                 }
1681                 synchronized (mSatelliteEnabledRequestLock) {
1682                     mSatelliteEnableAttributesUpdateRequest = null;
1683                 }
1684                 argument.callback.accept(error);
1685                 break;
1686             }
1687 
1688             case EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT: {
1689                 RequestSatelliteEnabledArgument argument =
1690                         (RequestSatelliteEnabledArgument) msg.obj;
1691                 plogw("Timed out to wait for the response from the modem for the request to "
1692                         + "update satellite enable attributes, request ID = " + argument.requestId);
1693                 synchronized (mSatelliteEnabledRequestLock) {
1694                     mSatelliteEnableAttributesUpdateRequest = null;
1695                 }
1696                 argument.callback.accept(SATELLITE_RESULT_MODEM_TIMEOUT);
1697                 break;
1698             }
1699 
1700             case CMD_IS_SATELLITE_ENABLED: {
1701                 request = (SatelliteControllerHandlerRequest) msg.obj;
1702                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request);
1703                 mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted);
1704                 break;
1705             }
1706 
1707             case EVENT_IS_SATELLITE_ENABLED_DONE: {
1708                 ar = (AsyncResult) msg.obj;
1709                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1710                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1711                         "isSatelliteEnabled");
1712                 Bundle bundle = new Bundle();
1713                 if (error == SATELLITE_RESULT_SUCCESS) {
1714                     if (ar.result == null) {
1715                         ploge("isSatelliteEnabled: result is null");
1716                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1717                     } else {
1718                         boolean enabled = ((int[]) ar.result)[0] == 1;
1719                         if (DBG) plogd("isSatelliteEnabled: " + enabled);
1720                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled);
1721                         updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE");
1722                     }
1723                 } else if (error == SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
1724                     updateSatelliteSupportedState(false);
1725                 }
1726                 ((ResultReceiver) request.argument).send(error, bundle);
1727                 decrementResultReceiverCount("SC:requestIsSatelliteEnabled");
1728                 break;
1729             }
1730 
1731             case CMD_IS_SATELLITE_SUPPORTED: {
1732                 request = (SatelliteControllerHandlerRequest) msg.obj;
1733                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request);
1734                 mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted);
1735                 break;
1736             }
1737 
1738             case EVENT_IS_SATELLITE_SUPPORTED_DONE: {
1739                 ar = (AsyncResult) msg.obj;
1740                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1741                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported");
1742                 Bundle bundle = new Bundle();
1743                 if (error == SATELLITE_RESULT_SUCCESS) {
1744                     if (ar.result == null) {
1745                         ploge("isSatelliteSupported: result is null");
1746                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1747                     } else {
1748                         boolean supported = (boolean) ar.result;
1749                         plogd("isSatelliteSupported: " + supported);
1750                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported);
1751                         updateSatelliteSupportedState(supported);
1752                     }
1753                 }
1754                 ((ResultReceiver) request.argument).send(error, bundle);
1755                 break;
1756             }
1757 
1758             case CMD_GET_SATELLITE_CAPABILITIES: {
1759                 request = (SatelliteControllerHandlerRequest) msg.obj;
1760                 onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request);
1761                 mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted);
1762                 break;
1763             }
1764 
1765             case EVENT_GET_SATELLITE_CAPABILITIES_DONE: {
1766                 ar = (AsyncResult) msg.obj;
1767                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1768                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1769                         "getSatelliteCapabilities");
1770                 Bundle bundle = new Bundle();
1771                 if (error == SATELLITE_RESULT_SUCCESS) {
1772                     if (ar.result == null) {
1773                         ploge("getSatelliteCapabilities: result is null");
1774                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1775                     } else {
1776                         SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result;
1777                         synchronized (mNeedsSatellitePointingLock) {
1778                             mNeedsSatellitePointing = capabilities.isPointingRequired();
1779                         }
1780 
1781                         synchronized (mSatelliteCapabilitiesLock) {
1782                             mSatelliteCapabilities = capabilities;
1783                         }
1784                         overrideSatelliteCapabilitiesIfApplicable();
1785                         if (DBG) plogd("getSatelliteCapabilities: " + getSatelliteCapabilities());
1786                         bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
1787                                 getSatelliteCapabilities());
1788                     }
1789                 }
1790                 ((ResultReceiver) request.argument).send(error, bundle);
1791                 break;
1792             }
1793 
1794             case CMD_GET_TIME_SATELLITE_NEXT_VISIBLE: {
1795                 request = (SatelliteControllerHandlerRequest) msg.obj;
1796                 onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE,
1797                         request);
1798                 mSatelliteModemInterface.requestTimeForNextSatelliteVisibility(onCompleted);
1799                 break;
1800             }
1801 
1802             case EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE: {
1803                 ar = (AsyncResult) msg.obj;
1804                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1805                 int error = SatelliteServiceUtils.getSatelliteError(ar,
1806                         "requestTimeForNextSatelliteVisibility");
1807                 Bundle bundle = new Bundle();
1808                 if (error == SATELLITE_RESULT_SUCCESS) {
1809                     if (ar.result == null) {
1810                         ploge("requestTimeForNextSatelliteVisibility: result is null");
1811                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1812                     } else {
1813                         int nextVisibilityDuration = ((int[]) ar.result)[0];
1814                         if (DBG) {
1815                             plogd("requestTimeForNextSatelliteVisibility: "
1816                                     + nextVisibilityDuration);
1817                         }
1818                         bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY,
1819                                 nextVisibilityDuration);
1820                     }
1821                 }
1822                 ((ResultReceiver) request.argument).send(error, bundle);
1823                 decrementResultReceiverCount("SC:requestTimeForNextSatelliteVisibility");
1824                 break;
1825             }
1826 
1827             case EVENT_RADIO_STATE_CHANGED: {
1828                 synchronized (mIsRadioOnLock) {
1829                     logd("EVENT_RADIO_STATE_CHANGED: radioState=" + mCi.getRadioState());
1830                     if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
1831                         mIsRadioOn = true;
1832                     } else if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) {
1833                         resetCarrierRoamingSatelliteModeParams();
1834                         synchronized (mIsRadioOnLock) {
1835                             if (mRadioOffRequested) {
1836                                 logd("EVENT_RADIO_STATE_CHANGED: set mIsRadioOn to false");
1837                                 stopWaitForCellularModemOffTimer();
1838                                 mIsRadioOn = false;
1839                                 mRadioOffRequested = false;
1840                             }
1841                         }
1842                     }
1843                 }
1844 
1845                 if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
1846                     if (mSatelliteModemInterface.isSatelliteServiceConnected()) {
1847                         Boolean isSatelliteSupported = getIsSatelliteSupported();
1848                         if (isSatelliteSupported == null || !isSatelliteSupported) {
1849                             final String caller = "SC:CMD_IS_SATELLITE_SUPPORTED";
1850                             ResultReceiver receiver = new ResultReceiver(this) {
1851                                 @Override
1852                                 protected void onReceiveResult(
1853                                         int resultCode, Bundle resultData) {
1854                                     decrementResultReceiverCount(caller);
1855                                     plogd("onRadioStateChanged.requestIsSatelliteSupported: "
1856                                             + "resultCode=" + resultCode
1857                                             + ", resultData=" + resultData);
1858                                 }
1859                             };
1860                             sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, receiver, null);
1861                             incrementResultReceiverCount(caller);
1862                         }
1863                     }
1864                 }
1865                 break;
1866             }
1867 
1868             case CMD_IS_SATELLITE_PROVISIONED: {
1869                 request = (SatelliteControllerHandlerRequest) msg.obj;
1870                 Message isProvisionedDoneEvent = this.obtainMessage(
1871                         EVENT_IS_SATELLITE_PROVISIONED_DONE,
1872                         new AsyncResult(request, SATELLITE_RESULT_SUCCESS, null));
1873                 isProvisionedDoneEvent.sendToTarget();
1874                 break;
1875             }
1876 
1877             case EVENT_IS_SATELLITE_PROVISIONED_DONE: {
1878                 handleIsSatelliteProvisionedDoneEvent((AsyncResult) msg.obj);
1879                 break;
1880             }
1881 
1882             case EVENT_PENDING_DATAGRAMS:
1883                 plogd("Received EVENT_PENDING_DATAGRAMS");
1884                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1885                     @Override
1886                     public void accept(int result) {
1887                         plogd("pollPendingSatelliteDatagram result: " + result);
1888                     }
1889                 };
1890                 pollPendingDatagrams(internalCallback);
1891                 break;
1892 
1893             case EVENT_SATELLITE_MODEM_STATE_CHANGED:
1894                 ar = (AsyncResult) msg.obj;
1895                 if (ar.result == null) {
1896                     ploge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null");
1897                 } else {
1898                     handleEventSatelliteModemStateChanged((int) ar.result);
1899                     updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(getSatellitePhone());
1900                 }
1901                 break;
1902 
1903             case EVENT_SET_SATELLITE_PLMN_INFO_DONE:
1904                 handleSetSatellitePlmnInfoDoneEvent(msg);
1905                 break;
1906 
1907             case CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE: {
1908                 plogd("CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE");
1909                 request = (SatelliteControllerHandlerRequest) msg.obj;
1910                 handleRequestSatelliteAttachRestrictionForCarrierCmd(request);
1911                 break;
1912             }
1913 
1914             case EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE: {
1915                 ar = (AsyncResult) msg.obj;
1916                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1917                 RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
1918                         (RequestHandleSatelliteAttachRestrictionForCarrierArgument)
1919                                 request.argument;
1920                 int subId = argument.subId;
1921                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1922                         "requestSetSatelliteEnabledForCarrier");
1923 
1924                 plogd("EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE: subId="
1925                         + subId + " error:" + error);
1926                 synchronized (mIsSatelliteEnabledLock) {
1927                     if (error == SATELLITE_RESULT_SUCCESS) {
1928                         boolean enableSatellite = mSatelliteAttachRestrictionForCarrierArray
1929                                 .getOrDefault(argument.subId, Collections.emptySet()).isEmpty();
1930                         plogd("EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE: "
1931                                 + "satelliteAttachEnabledForCarrier=" + enableSatellite);
1932                         mIsSatelliteAttachEnabledForCarrierArrayPerSub.put(subId, enableSatellite);
1933                     } else {
1934                         mIsSatelliteAttachEnabledForCarrierArrayPerSub.remove(subId);
1935                     }
1936                 }
1937 
1938                 argument.callback.accept(error);
1939                 break;
1940             }
1941 
1942             case CMD_REQUEST_NTN_SIGNAL_STRENGTH: {
1943                 plogd("CMD_REQUEST_NTN_SIGNAL_STRENGTH");
1944                 request = (SatelliteControllerHandlerRequest) msg.obj;
1945                 onCompleted = obtainMessage(EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE, request);
1946                 mSatelliteModemInterface.requestNtnSignalStrength(onCompleted);
1947                 break;
1948             }
1949 
1950             case EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: {
1951                 ar = (AsyncResult) msg.obj;
1952                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1953                 ResultReceiver result = (ResultReceiver) request.argument;
1954                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
1955                         "requestNtnSignalStrength");
1956                 if (errorCode == SATELLITE_RESULT_SUCCESS) {
1957                     NtnSignalStrength ntnSignalStrength = (NtnSignalStrength) ar.result;
1958                     if (ntnSignalStrength != null) {
1959                         synchronized (mNtnSignalsStrengthLock) {
1960                             mNtnSignalStrength = ntnSignalStrength;
1961                         }
1962                         Bundle bundle = new Bundle();
1963                         bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, ntnSignalStrength);
1964                         result.send(SATELLITE_RESULT_SUCCESS, bundle);
1965                     } else {
1966                         synchronized (mNtnSignalsStrengthLock) {
1967                             if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
1968                                 mNtnSignalStrength = new NtnSignalStrength(
1969                                         NTN_SIGNAL_STRENGTH_NONE);
1970                             }
1971                         }
1972                         ploge("EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: ntnSignalStrength is null");
1973                         result.send(SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED, null);
1974                     }
1975                 } else {
1976                     synchronized (mNtnSignalsStrengthLock) {
1977                         if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
1978                             mNtnSignalStrength = new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
1979                         }
1980                     }
1981                     result.send(errorCode, null);
1982                 }
1983                 decrementResultReceiverCount("SC:requestNtnSignalStrength");
1984                 break;
1985             }
1986 
1987             case EVENT_NTN_SIGNAL_STRENGTH_CHANGED: {
1988                 ar = (AsyncResult) msg.obj;
1989                 if (ar.result == null) {
1990                     ploge("EVENT_NTN_SIGNAL_STRENGTH_CHANGED: result is null");
1991                 } else {
1992                     handleEventNtnSignalStrengthChanged((NtnSignalStrength) ar.result);
1993                     updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(getSatellitePhone());
1994                 }
1995                 break;
1996             }
1997 
1998             case CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: {
1999                 ar = (AsyncResult) msg.obj;
2000                 boolean shouldReport = (boolean) ar.result;
2001                 if (DBG) {
2002                     plogd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: shouldReport=" + shouldReport);
2003                 }
2004                 handleCmdUpdateNtnSignalStrengthReporting(shouldReport);
2005                 break;
2006             }
2007 
2008             case EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: {
2009                 ar = (AsyncResult) msg.obj;
2010                 request = (SatelliteControllerHandlerRequest) ar.userObj;
2011                 boolean shouldReport = (boolean) request.argument;
2012                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
2013                         "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: shouldReport="
2014                                 + shouldReport);
2015                 if (errorCode == SATELLITE_RESULT_SUCCESS) {
2016                     mIsModemEnabledReportingNtnSignalStrength.set(shouldReport);
2017                     if (mLatestRequestedStateForNtnSignalStrengthReport.get()
2018                             != mIsModemEnabledReportingNtnSignalStrength.get()) {
2019                         logd("mLatestRequestedStateForNtnSignalStrengthReport does not match with "
2020                                 + "mIsModemEnabledReportingNtnSignalStrength");
2021                         updateNtnSignalStrengthReporting(
2022                                 mLatestRequestedStateForNtnSignalStrengthReport.get());
2023                     }
2024                 } else {
2025                     loge(((boolean) request.argument ? "startSendingNtnSignalStrength"
2026                             : "stopSendingNtnSignalStrength") + "returns " + errorCode);
2027                 }
2028                 break;
2029             }
2030 
2031             case EVENT_SERVICE_STATE_CHANGED: {
2032                 handleEventServiceStateChanged();
2033                 break;
2034             }
2035 
2036             case EVENT_SATELLITE_CAPABILITIES_CHANGED: {
2037                 ar = (AsyncResult) msg.obj;
2038                 if (ar.result == null) {
2039                     ploge("EVENT_SATELLITE_CAPABILITIES_CHANGED: result is null");
2040                 } else {
2041                     handleEventSatelliteCapabilitiesChanged((SatelliteCapabilities) ar.result);
2042                 }
2043                 break;
2044             }
2045 
2046             case EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: {
2047                 ar = (AsyncResult) msg.obj;
2048                 if (ar.result == null) {
2049                     ploge("EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: result is null");
2050                 } else {
2051                     handleEventSatelliteSupportedStateChanged((boolean) ar.result);
2052                 }
2053                 break;
2054             }
2055 
2056             case EVENT_SATELLITE_CONFIG_DATA_UPDATED: {
2057                 handleEventConfigDataUpdated();
2058                 mSatelliteConfigUpdateChangedRegistrants.notifyRegistrants();
2059                 break;
2060             }
2061 
2062             case EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT: {
2063                 int phoneId = (int) msg.obj;
2064                 Phone phone = PhoneFactory.getPhone(phoneId);
2065                 updateLastNotifiedNtnModeAndNotify(phone);
2066                 break;
2067             }
2068 
2069             case EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT: {
2070                 boolean eligible = isCarrierRoamingNtnEligible(mSatellitePhone);
2071                 plogd("EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT:"
2072                         + " isCarrierRoamingNtnEligible=" + eligible);
2073                 updateLastNotifiedNtnEligibilityAndNotify(eligible);
2074                 break;
2075             }
2076 
2077             case CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION: {
2078                 evaluateESOSProfilesPrioritization();
2079                 break;
2080             }
2081 
2082             case CMD_UPDATE_PROVISION_SATELLITE_TOKEN: {
2083                 request = (SatelliteControllerHandlerRequest) msg.obj;
2084                 RequestProvisionSatelliteArgument argument =
2085                         (RequestProvisionSatelliteArgument) request.argument;
2086                 onCompleted = obtainMessage(EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE, request);
2087                 boolean provisionChanged = updateSatelliteSubscriptionProvisionState(
2088                         argument.mSatelliteSubscriberInfoList, argument.mProvisioned);
2089                 selectBindingSatelliteSubscription(false);
2090                 int subId = getSelectedSatelliteSubId();
2091                 SubscriptionInfo subscriptionInfo =
2092                     mSubscriptionManagerService.getSubscriptionInfo(subId);
2093                 if (subscriptionInfo == null) {
2094                     logw("updateSatelliteToken subId=" + subId + " is not found");
2095                 } else {
2096                     String iccId = subscriptionInfo.getIccId();
2097                     argument.setIccId(iccId);
2098                     synchronized (mSatelliteTokenProvisionedLock) {
2099                         if (!iccId.equals(mLastConfiguredIccId)) {
2100                             logd("updateSatelliteSubscription subId=" + subId
2101                                     + ", iccId=" + iccId + " to modem");
2102                             mSatelliteModemInterface.updateSatelliteSubscription(
2103                                 iccId, onCompleted);
2104                         }
2105                     }
2106                 }
2107                 if (provisionChanged) {
2108                     handleEventSatelliteSubscriptionProvisionStateChanged();
2109                 }
2110 
2111                 // The response is sent immediately because the ICCID has already been
2112                 // delivered to the modem.
2113                 Bundle bundle = new Bundle();
2114                 bundle.putBoolean(
2115                         argument.mProvisioned ? SatelliteManager.KEY_PROVISION_SATELLITE_TOKENS
2116                                 : SatelliteManager.KEY_DEPROVISION_SATELLITE_TOKENS, true);
2117                 argument.mResult.send(SATELLITE_RESULT_SUCCESS, bundle);
2118                 decrementResultReceiverCount("SC:provisionSatellite");
2119                 break;
2120             }
2121 
2122             case EVENT_UPDATE_PROVISION_SATELLITE_TOKEN_DONE: {
2123                 ar = (AsyncResult) msg.obj;
2124                 request = (SatelliteControllerHandlerRequest) ar.userObj;
2125                 RequestProvisionSatelliteArgument argument =
2126                         (RequestProvisionSatelliteArgument) request.argument;
2127                 int error = SatelliteServiceUtils.getSatelliteError(ar,
2128                         "updateSatelliteSubscription");
2129                 if (error == SATELLITE_RESULT_SUCCESS) {
2130                     synchronized (mSatelliteTokenProvisionedLock) {
2131                         mLastConfiguredIccId = argument.getIccId();
2132                     }
2133                 }
2134                 mProvisionMetricsStats.setResultCode(error)
2135                         .setIsProvisionRequest(argument.mProvisioned)
2136                         .setCarrierId(getSatelliteCarrierId())
2137                         .setIsNtnOnlyCarrier(isNtnOnlyCarrier())
2138                         .reportProvisionMetrics();
2139                 if (argument.mProvisioned) {
2140                     mControllerMetricsStats.reportProvisionCount(error);
2141                 } else {
2142                     mControllerMetricsStats.reportDeprovisionCount(error);
2143                 }
2144                 logd("updateSatelliteSubscription result=" + error);
2145                 break;
2146             }
2147 
2148             case EVENT_WIFI_CONNECTIVITY_STATE_CHANGED: {
2149                 synchronized (mIsWifiConnectedLock) {
2150                     ar = (AsyncResult) msg.obj;
2151                     mIsWifiConnected = (boolean) ar.result;
2152                     plogd("EVENT_WIFI_CONNECTIVITY_STATE_CHANGED: mIsWifiConnected="
2153                             + mIsWifiConnected);
2154                 }
2155                 evaluateCarrierRoamingNtnEligibilityChange();
2156                 break;
2157             }
2158 
2159             case EVENT_WAIT_FOR_CELLULAR_MODEM_OFF_TIMED_OUT: {
2160                 plogw("Timed out to wait for cellular modem OFF state");
2161                 synchronized (mIsRadioOnLock) {
2162                     mRadioOffRequested = false;
2163                 }
2164                 break;
2165             }
2166 
2167             case EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT: {
2168                 // TODO: b/366329504 report carrier roaming metrics for multiple subscription IDs.
2169                 synchronized (mSupportedSatelliteServicesLock) {
2170                     int defaultSubId = mSubscriptionManagerService.getDefaultSubId();
2171                     boolean isEntitled = mSatelliteEntitlementStatusPerCarrier.get(defaultSubId,
2172                             false);
2173                     mCarrierRoamingSatelliteControllerStats.reportIsDeviceEntitled(defaultSubId,
2174                             isEntitled);
2175                 }
2176                 sendMessageDelayed(obtainMessage(
2177                                 EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT),
2178                         WAIT_FOR_REPORT_ENTITLED_MERTICS_TIMEOUT_MILLIS);
2179                 break;
2180             }
2181 
2182             case EVENT_SATELLITE_REGISTRATION_FAILURE:
2183                 ar = (AsyncResult) msg.obj;
2184                 if (ar.result == null) {
2185                     loge("EVENT_SATELLITE_REGISTRATION_FAILURE: result is null");
2186                 } else {
2187                     handleEventSatelliteRegistrationFailure((int) ar.result);
2188                 }
2189                 break;
2190 
2191             case EVENT_TERRESTRIAL_NETWORK_AVAILABLE_CHANGED:
2192                 ar = (AsyncResult) msg.obj;
2193                 if (ar.result == null) {
2194                     loge("EVENT_TERRESTRIAL_NETWORK_AVAILABLE_CHANGED: result is null");
2195                 } else {
2196                     handleEventTerrestrialNetworkAvailableChanged((boolean) ar.result);
2197                 }
2198                 break;
2199 
2200             case EVENT_SET_NETWORK_SELECTION_AUTO_DONE: {
2201                 logd("EVENT_SET_NETWORK_SELECTION_AUTO_DONE");
2202                 RequestSatelliteEnabledArgument argument =
2203                         (RequestSatelliteEnabledArgument) msg.obj;
2204                 sendRequestAsync(CMD_SET_SATELLITE_ENABLED, argument, null);
2205                 break;
2206             }
2207 
2208             case EVENT_SIGNAL_STRENGTH_CHANGED: {
2209                 ar = (AsyncResult) msg.obj;
2210                 int phoneId = (int) ar.userObj;
2211                 updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(
2212                         PhoneFactory.getPhone(phoneId));
2213                 break;
2214             }
2215 
2216             case CMD_UPDATE_SYSTEM_SELECTION_CHANNELS: {
2217                 plogd("CMD_UPDATE_SYSTEM_SELECTION_CHANNELS");
2218                 request = (SatelliteControllerHandlerRequest) msg.obj;
2219                 onCompleted =
2220                     obtainMessage(EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE, request);
2221                 UpdateSystemSelectionChannelsArgument argument =
2222                         (UpdateSystemSelectionChannelsArgument) request.argument;
2223                 mSatelliteModemInterface.updateSystemSelectionChannels(
2224                         argument.systemSelectionSpecifiers, onCompleted);
2225                 startWaitForUpdateSystemSelectionChannelsResponseTimer(argument);
2226                 break;
2227             }
2228 
2229             case EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE: {
2230                 ar = (AsyncResult) msg.obj;
2231                 request = (SatelliteControllerHandlerRequest) ar.userObj;
2232                 int error =  SatelliteServiceUtils.getSatelliteError(
2233                         ar, "updateSystemSelectionChannel");
2234                 plogd("EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE = " + error);
2235                 UpdateSystemSelectionChannelsArgument argument =
2236                         (UpdateSystemSelectionChannelsArgument) request.argument;
2237                 if (shouldProcessEventUpdateSystemSelectionChannelsDone(argument)) {
2238                     argument.result.send(error, null);
2239                     stopWaitForUpdateSystemSelectionChannelsResponseTimer(argument);
2240                 } else {
2241                     plogd("EVENT_UPDATE_SYSTEM_SELECTION_CHANNELS_DONE: the timer of "
2242                               + "the request ID " + argument.requestId
2243                               + " has already expired.");
2244                 }
2245                 break;
2246             }
2247 
2248             case EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT: {
2249                 UpdateSystemSelectionChannelsArgument argument =
2250                         (UpdateSystemSelectionChannelsArgument) msg.obj;
2251                 argument.result.send(SATELLITE_RESULT_MODEM_TIMEOUT, null);
2252                 plogd("Timed out to wait for response of the system selection channels"
2253                           + " update request ID " + argument.requestId);
2254                 break;
2255             }
2256 
2257             case EVENT_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_CHANGED: {
2258                 ar = (AsyncResult) msg.obj;
2259                 if (ar.result == null) {
2260                     loge("EVENT_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_CHANGED: result is null");
2261                 } else {
2262                     handleEventSelectedNbIotSatelliteSubscriptionChanged((int) ar.result);
2263                 }
2264                 break;
2265             }
2266 
2267             case CMD_LOCATION_SERVICE_STATE_CHANGED:
2268                 plogd("CMD_LOCATION_SERVICE_STATE_CHANGED");
2269                 // Fall through
2270             case CMD_EVALUATE_CARRIER_ROAMING_NTN_ELIGIBILITY_CHANGE: {
2271                 plogd("CMD_EVALUATE_CARRIER_ROAMING_NTN_ELIGIBILITY_CHANGE");
2272                 evaluateCarrierRoamingNtnEligibilityChange();
2273                 boolean eligible = isCarrierRoamingNtnEligible(getSatellitePhone());
2274                 plogd("CMD_EVALUATE_CARRIER_ROAMING_NTN_ELIGIBILITY_CHANGE: eligible=" + eligible);
2275                 int selectedSatelliteSubId = getSelectedSatelliteSubId();
2276                 Phone phone = SatelliteServiceUtils.getPhone(selectedSatelliteSubId);
2277                 if (eligible) {
2278                     synchronized (mSatellitePhoneLock) {
2279                         mLastNotifiedNtnEligibility = eligible;
2280                     }
2281                     phone.notifyCarrierRoamingNtnEligibleStateChanged(eligible);
2282                 }
2283                 break;
2284             }
2285 
2286             case CMD_GET_SATELLITE_ENABLED_FOR_CARRIER: {
2287                 request = (SatelliteControllerHandlerRequest) msg.obj;
2288                 Phone phone = request.phone;
2289                 int subId = phone.getSubId();
2290                 onCompleted = obtainMessage(EVENT_GET_SATELLITE_ENABLED_FOR_CARRIER_DONE,
2291                         subId);
2292                 int simSlot = SubscriptionManager.getSlotIndex(subId);
2293                 plogd("CMD_GET_SATELLITE_ENABLED_FOR_CARRIER: subId=" + subId);
2294                 phone.isSatelliteEnabledForCarrier(simSlot, onCompleted);
2295                 break;
2296             }
2297 
2298             case EVENT_GET_SATELLITE_ENABLED_FOR_CARRIER_DONE: {
2299                 ar = (AsyncResult) msg.obj;
2300 
2301                 if (ar.result == null) {
2302                     loge("EVENT_GET_SATELLITE_ENABLED_FOR_CARRIER_DONE: result is null");
2303                 } else {
2304                     int subId = (int) ar.userObj;
2305                     int error = SatelliteServiceUtils.getSatelliteError(
2306                             ar, "isSatelliteEnabledForCarrier");
2307                     boolean satelliteEnabled = (Boolean) ar.result;
2308                     plogd("EVENT_GET_SATELLITE_ENABLED_FOR_CARRIER_DONE: subId=" + subId
2309                             + " error=" + error + " satelliteEnabled=" + satelliteEnabled);
2310 
2311                     if (error == SATELLITE_RESULT_SUCCESS) {
2312                         synchronized (mIsSatelliteEnabledLock) {
2313                             mIsSatelliteAttachEnabledForCarrierArrayPerSub.put(
2314                                     subId, satelliteEnabled);
2315                         }
2316                         evaluateEnablingSatelliteForCarrier(subId,
2317                                 SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, null);
2318                     }
2319                 }
2320                 break;
2321             }
2322 
2323             default:
2324                 Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
2325                         msg.what);
2326                 break;
2327         }
2328     }
2329 
2330     private static final class RequestProvisionSatelliteArgument {
2331         public List<SatelliteSubscriberInfo> mSatelliteSubscriberInfoList;
2332         @NonNull
2333         public ResultReceiver mResult;
2334         public long mRequestId;
2335         public String mIccId;
2336         public boolean mProvisioned;
2337 
RequestProvisionSatelliteArgument(List<SatelliteSubscriberInfo> satelliteSubscriberInfoList, ResultReceiver result, boolean provisioned)2338         RequestProvisionSatelliteArgument(List<SatelliteSubscriberInfo> satelliteSubscriberInfoList,
2339                 ResultReceiver result, boolean provisioned) {
2340             this.mSatelliteSubscriberInfoList = satelliteSubscriberInfoList;
2341             this.mResult = result;
2342             this.mProvisioned = provisioned;
2343             this.mRequestId = sNextSatelliteEnableRequestId.getAndUpdate(
2344                     n -> ((n + 1) % Long.MAX_VALUE));
2345         }
2346 
setIccId(String iccId)2347         public void setIccId(String iccId) {
2348             mIccId = iccId;
2349         }
2350 
getIccId()2351         public String getIccId() {
2352             return mIccId;
2353         }
2354     }
2355 
handleEventConfigDataUpdated()2356     private void handleEventConfigDataUpdated() {
2357         updateSupportedSatelliteServicesForActiveSubscriptions();
2358         int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
2359         if (activeSubIds != null) {
2360             for (int subId : activeSubIds) {
2361                 processNewCarrierConfigData(subId);
2362             }
2363         } else {
2364             ploge("updateSupportedSatelliteServicesForActiveSubscriptions: "
2365                     + "activeSubIds is null");
2366         }
2367     }
2368 
notifyRequester(SatelliteControllerHandlerRequest request)2369     private void notifyRequester(SatelliteControllerHandlerRequest request) {
2370         synchronized (request) {
2371             request.notifyAll();
2372         }
2373     }
2374 
2375     /**
2376      * Request to enable or disable the satellite modem and demo mode. If the satellite modem is
2377      * enabled, this will also disable the cellular modem, and if the satellite modem is disabled,
2378      * this will also re-enable the cellular modem.
2379      *
2380      * @param enableSatellite {@code true} to enable the satellite modem and
2381      *                        {@code false} to disable.
2382      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
2383      * @param isEmergency {@code true} to enable emergency mode, {@code false} otherwise.
2384      * @param callback The callback to get the error code of the request.
2385      */
requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, @NonNull IIntegerConsumer callback)2386     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
2387             boolean isEmergency, @NonNull IIntegerConsumer callback) {
2388         plogd("requestSatelliteEnabled enableSatellite: " + enableSatellite
2389                 + " enableDemoMode: " + enableDemoMode + " isEmergency: " + isEmergency);
2390         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2391         int error = evaluateOemSatelliteRequestAllowed(true);
2392         if (error != SATELLITE_RESULT_SUCCESS) {
2393             sendErrorAndReportSessionMetrics(error, result);
2394             return;
2395         }
2396 
2397         if (enableSatellite) {
2398             synchronized (mIsRadioOnLock) {
2399                 if (!mIsRadioOn) {
2400                     ploge("Radio is not on, can not enable satellite");
2401                     sendErrorAndReportSessionMetrics(
2402                             SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
2403                     return;
2404                 }
2405                 if (mRadioOffRequested) {
2406                     ploge("Radio is being powering off, can not enable satellite");
2407                     sendErrorAndReportSessionMetrics(
2408                             SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
2409                     return;
2410                 }
2411             }
2412 
2413             if (mTelecomManager.isInEmergencyCall()) {
2414                 plogd("requestSatelliteEnabled: reject as emergency call is ongoing.");
2415                 sendErrorAndReportSessionMetrics(
2416                         SatelliteManager.SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS, result);
2417                 return;
2418             }
2419         } else {
2420             /* if disable satellite, always assume demo is also disabled */
2421             enableDemoMode = false;
2422         }
2423 
2424         RequestSatelliteEnabledArgument request =
2425                 new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, isEmergency,
2426                         result);
2427         /**
2428          * Multiple satellite enabled requests are handled as below:
2429          * 1. If there are no ongoing requests, store current request in mSatelliteEnabledRequest
2430          * 2. If there is a ongoing request, then:
2431          *      1. ongoing request = enable, current request = enable: return IN_PROGRESS error
2432          *      2. ongoing request = disable, current request = disable: return IN_PROGRESS error
2433          *      3. ongoing request = disable, current request = enable: return
2434          *      SATELLITE_RESULT_ERROR error
2435          *      4. ongoing request = enable, current request = disable: send request to modem
2436          */
2437         Boolean isSatelliteEnabled = getIsSatelliteEnabled();
2438         synchronized (mSatelliteEnabledRequestLock) {
2439             if (mFeatureFlags.carrierRoamingNbIotNtn()) {
2440                 if (mSatelliteEnabledRequest != null && mNetworkSelectionModeAutoDialog != null
2441                         && mNetworkSelectionModeAutoDialog.isShowing()
2442                         && request.isEmergency && request.enableSatellite) {
2443                     sendErrorAndReportSessionMetrics(
2444                             SatelliteManager.SATELLITE_RESULT_ILLEGAL_STATE,
2445                             FunctionalUtils.ignoreRemoteException(
2446                                     mSatelliteEnabledRequest.callback::accept));
2447                     mSatelliteEnabledRequest = null;
2448                     mNetworkSelectionModeAutoDialog.dismiss();
2449                     mNetworkSelectionModeAutoDialog = null;
2450                 }
2451             }
2452             if (!isSatelliteEnabledRequestInProgress()) {
2453                 if (isSatelliteEnabled != null && isSatelliteEnabled == enableSatellite) {
2454                     evaluateToUpdateSatelliteEnabledAttributes(result,
2455                             SatelliteManager.SATELLITE_RESULT_SUCCESS, request,
2456                             mIsDemoModeEnabled, mIsEmergency);
2457                     return;
2458                 }
2459 
2460                 if (enableSatellite) {
2461                     mSatelliteEnabledRequest = request;
2462                 } else {
2463                     mSatelliteDisabledRequest = request;
2464                 }
2465             } else if (isSatelliteBeingDisabled()) {
2466                 int resultCode = SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS;
2467                 if (enableSatellite) {
2468                     plogw("requestSatelliteEnabled: The enable request cannot be "
2469                             + "processed since disable satellite is in progress.");
2470                     resultCode = SatelliteManager.SATELLITE_RESULT_DISABLE_IN_PROGRESS;
2471                 } else {
2472                     plogd("requestSatelliteEnabled: Disable is already in progress.");
2473                 }
2474                 sendErrorAndReportSessionMetrics(resultCode, result);
2475                 return;
2476             } else {
2477                 // Satellite is being enabled or satellite enable attributes are being updated
2478                 if (enableSatellite) {
2479                     if (mSatelliteEnableAttributesUpdateRequest == null) {
2480                         /* Satellite is being enabled and framework receive a new enable request to
2481                          * update the enable attributes.
2482                          */
2483                         evaluateToUpdateSatelliteEnabledAttributes(result,
2484                                 SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS,
2485                                 request, mSatelliteEnabledRequest.enableDemoMode,
2486                                 mSatelliteEnabledRequest.isEmergency);
2487                     } else {
2488                         /* The enable attributes update request is already being processed.
2489                          * Framework can't handle one more request to update enable attributes.
2490                          */
2491                         plogd("requestSatelliteEnabled: enable attributes update request is already"
2492                                 + " in progress.");
2493                         sendErrorAndReportSessionMetrics(
2494                                 SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS, result);
2495                     }
2496                     return;
2497                 } else {
2498                     /* Users might want to end the satellite session while it is being enabled, or
2499                      * the satellite session need to be disabled for an emergency call. Note: some
2500                      * carriers want to disable satellite for prioritizing emergency calls. Thus,
2501                      * we need to push the disable request to modem while enable is in progress.
2502                      */
2503                     if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
2504                         plogd("requestSatelliteEnabled: carrierRoamingNbIotNtn flag is disabled");
2505                         sendErrorAndReportSessionMetrics(
2506                                 SatelliteManager.SATELLITE_RESULT_ENABLE_IN_PROGRESS, result);
2507                         return;
2508                     }
2509                     if (!isDisableSatelliteWhileEnableInProgressSupported()) {
2510                         plogd("requestSatelliteEnabled: disable satellite while enable in progress"
2511                                 + " is not supported");
2512                         sendErrorAndReportSessionMetrics(
2513                                 SatelliteManager.SATELLITE_RESULT_ENABLE_IN_PROGRESS, result);
2514                         return;
2515                     }
2516                     mSatelliteDisabledRequest = request;
2517                 }
2518             }
2519         }
2520 
2521         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
2522             Phone satellitePhone = getSatellitePhone();
2523             if (enableSatellite && satellitePhone != null
2524                     && satellitePhone.getServiceStateTracker() != null
2525                     && satellitePhone.getServiceStateTracker().getServiceState()
2526                     .getIsManualSelection()) {
2527                 checkNetworkSelectionModeAuto(request);
2528             } else {
2529                 sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
2530             }
2531         } else {
2532             sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
2533         }
2534     }
2535 
isDisableSatelliteWhileEnableInProgressSupported()2536     private boolean isDisableSatelliteWhileEnableInProgressSupported() {
2537         if (mOverriddenDisableSatelliteWhileEnableInProgressSupported != null) {
2538             return mOverriddenDisableSatelliteWhileEnableInProgressSupported;
2539         }
2540         return mContext.getResources().getBoolean(
2541             R.bool.config_support_disable_satellite_while_enable_in_progress);
2542     }
2543 
checkNetworkSelectionModeAuto(RequestSatelliteEnabledArgument argument)2544     private void checkNetworkSelectionModeAuto(RequestSatelliteEnabledArgument argument) {
2545         plogd("checkNetworkSelectionModeAuto");
2546         if (argument.isEmergency) {
2547             // ESOS
2548             getSatellitePhone().setNetworkSelectionModeAutomatic(null);
2549             sendMessageDelayed(obtainMessage(EVENT_SET_NETWORK_SELECTION_AUTO_DONE, argument),
2550                     DELAY_WAITING_SET_NETWORK_SELECTION_AUTO_MILLIS);
2551         } else {
2552             // P2P
2553             if (mNetworkSelectionModeAutoDialog != null
2554                     && mNetworkSelectionModeAutoDialog.isShowing()) {
2555                 logd("requestSatelliteEnabled: already auto network selection mode popup showing");
2556                 sendErrorAndReportSessionMetrics(
2557                         SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS,
2558                         FunctionalUtils.ignoreRemoteException(argument.callback::accept));
2559                 return;
2560             }
2561             logd("requestSatelliteEnabled: auto network selection mode popup");
2562             Configuration configuration = Resources.getSystem().getConfiguration();
2563             boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
2564                     == Configuration.UI_MODE_NIGHT_YES;
2565 
2566             AlertDialog.Builder builder = new AlertDialog.Builder(mContext, nightMode
2567                     ? AlertDialog.THEME_DEVICE_DEFAULT_DARK
2568                     : AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
2569 
2570             String title = mContext.getResources().getString(
2571                     R.string.satellite_manual_selection_state_popup_title);
2572             String message = mContext.getResources().getString(
2573                     R.string.satellite_manual_selection_state_popup_message);
2574             String ok = mContext.getResources().getString(
2575                     R.string.satellite_manual_selection_state_popup_ok);
2576             String cancel = mContext.getResources().getString(
2577                     R.string.satellite_manual_selection_state_popup_cancel);
2578 
2579             builder.setTitle(title).setMessage(message)
2580                     .setPositiveButton(ok, (dialog, which) -> {
2581                         logd("checkNetworkSelectionModeAuto: setPositiveButton");
2582                         getSatellitePhone().setNetworkSelectionModeAutomatic(null);
2583                         sendMessageDelayed(obtainMessage(EVENT_SET_NETWORK_SELECTION_AUTO_DONE,
2584                                 argument), DELAY_WAITING_SET_NETWORK_SELECTION_AUTO_MILLIS);
2585                     })
2586                     .setNegativeButton(cancel, (dialog, which) -> {
2587                         logd("checkNetworkSelectionModeAuto: setNegativeButton");
2588                         synchronized (mSatelliteEnabledRequestLock) {
2589                             mSatelliteEnabledRequest = null;
2590                         }
2591                         sendErrorAndReportSessionMetrics(
2592                                 SatelliteManager.SATELLITE_RESULT_ILLEGAL_STATE,
2593                                 FunctionalUtils.ignoreRemoteException(argument.callback::accept));
2594                     })
2595                     .setOnCancelListener(dialog -> {
2596                         logd("checkNetworkSelectionModeAuto: setOnCancelListener");
2597                         synchronized (mSatelliteEnabledRequestLock) {
2598                             mSatelliteEnabledRequest = null;
2599                         }
2600                         sendErrorAndReportSessionMetrics(
2601                                 SatelliteManager.SATELLITE_RESULT_ILLEGAL_STATE,
2602                                 FunctionalUtils.ignoreRemoteException(argument.callback::accept));
2603                     });
2604             mNetworkSelectionModeAutoDialog = builder.create();
2605             mNetworkSelectionModeAutoDialog.getWindow()
2606                     .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2607             mNetworkSelectionModeAutoDialog.show();
2608         }
2609     }
2610 
2611     /**
2612      * Validate the newly-received enable attributes against the current ones. If the new attributes
2613      * are valid and different from the current ones, framework will send a request to update the
2614      * enable attributes to modem. Otherwise, framework will return
2615      * {@code SATELLITE_RESULT_INVALID_ARGUMENTS} to the requesting clients.
2616      *
2617      * @param result The callback that returns the result to the requesting client.
2618      * @param resultCode The result code to send back to the requesting client when framework does
2619      *                   not need to reconfigure modem.
2620      * @param enableRequest The new enable request to update satellite enable attributes.
2621      * @param currentDemoMode The current demo mode at framework.
2622      * @param currentEmergencyMode The current emergency mode at framework.
2623      */
evaluateToUpdateSatelliteEnabledAttributes(@onNull Consumer<Integer> result, @SatelliteManager.SatelliteResult int resultCode, @NonNull RequestSatelliteEnabledArgument enableRequest, boolean currentDemoMode, boolean currentEmergencyMode)2624     private void evaluateToUpdateSatelliteEnabledAttributes(@NonNull Consumer<Integer> result,
2625             @SatelliteManager.SatelliteResult int resultCode,
2626             @NonNull RequestSatelliteEnabledArgument enableRequest, boolean currentDemoMode,
2627             boolean currentEmergencyMode) {
2628         boolean needToReconfigureModem = false;
2629         if (enableRequest.enableDemoMode != currentDemoMode) {
2630             if (enableRequest.enableDemoMode) {
2631                 ploge("Moving from real mode to demo mode is rejected");
2632                 sendErrorAndReportSessionMetrics(SATELLITE_RESULT_INVALID_ARGUMENTS, result);
2633                 return;
2634             } else {
2635                 plogd("Moving from demo mode to real mode. Need to reconfigure"
2636                         + " modem with real mode");
2637                 needToReconfigureModem = true;
2638             }
2639         } else if (enableRequest.isEmergency != currentEmergencyMode) {
2640             if (enableRequest.isEmergency) {
2641                 plogd("Moving from non-emergency to emergency mode. Need to "
2642                         + "reconfigure modem");
2643                 needToReconfigureModem = true;
2644             } else {
2645                 plogd("Non-emergency requests can be served during an emergency"
2646                         + " satellite session. No need to reconfigure modem.");
2647             }
2648         }
2649 
2650         if (needToReconfigureModem) {
2651             synchronized (mSatelliteEnabledRequestLock) {
2652                 mSatelliteEnableAttributesUpdateRequest = enableRequest;
2653             }
2654             sendRequestAsync(
2655                     CMD_UPDATE_SATELLITE_ENABLE_ATTRIBUTES, enableRequest, null);
2656         } else {
2657             if (resultCode != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
2658                 plogd("requestSatelliteEnabled enable satellite is already in progress.");
2659             }
2660             sendErrorAndReportSessionMetrics(resultCode, result);
2661         }
2662         return;
2663     }
2664 
2665     /**
2666      * @return {@code true} when either enable request, disable request, or enable attributes update
2667      * request is in progress, {@code false} otherwise.
2668      */
isSatelliteEnabledRequestInProgress()2669     private boolean isSatelliteEnabledRequestInProgress() {
2670         synchronized (mSatelliteEnabledRequestLock) {
2671             plogd("mSatelliteEnabledRequest: " + (mSatelliteEnabledRequest != null)
2672                     + ", mSatelliteDisabledRequest: " + (mSatelliteDisabledRequest != null)
2673                     + ", mSatelliteEnableAttributesUpdateRequest: "
2674                     + (mSatelliteEnableAttributesUpdateRequest != null));
2675             return (mSatelliteEnabledRequest != null || mSatelliteDisabledRequest != null
2676                     || mSatelliteEnableAttributesUpdateRequest != null);
2677         }
2678     }
2679 
2680     /**
2681      * Request to get whether the satellite modem is enabled.
2682      *
2683      * @param result The result receiver that returns whether the satellite modem is enabled
2684      *               if the request is successful or an error code if the request failed.
2685      */
requestIsSatelliteEnabled(@onNull ResultReceiver result)2686     public void requestIsSatelliteEnabled(@NonNull ResultReceiver result) {
2687         int error = evaluateOemSatelliteRequestAllowed(false);
2688         if (error != SATELLITE_RESULT_SUCCESS) {
2689             result.send(error, null);
2690             return;
2691         }
2692 
2693         Boolean isSatelliteEnabled = getIsSatelliteEnabled();
2694         if (isSatelliteEnabled != null) {
2695             /* We have already successfully queried the satellite modem. */
2696             Bundle bundle = new Bundle();
2697             bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, isSatelliteEnabled);
2698             result.send(SATELLITE_RESULT_SUCCESS, bundle);
2699             return;
2700         }
2701 
2702         sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, null);
2703         incrementResultReceiverCount("SC:requestIsSatelliteEnabled");
2704     }
2705 
2706     /**
2707      * Get whether the satellite modem is enabled.
2708      * This will return the cached value instead of querying the satellite modem.
2709      *
2710      * @return {@code true} if the satellite modem is enabled and {@code false} otherwise.
2711      */
isSatelliteEnabled()2712     public boolean isSatelliteEnabled() {
2713         synchronized (mIsSatelliteEnabledLock) {
2714             if (mIsSatelliteEnabled == null) return false;
2715             return mIsSatelliteEnabled;
2716         }
2717     }
2718 
2719     /**
2720      * Get whether satellite modem is being enabled.
2721      *
2722      * @return {@code true} if the satellite modem is being enabled and {@code false} otherwise.
2723      */
isSatelliteBeingEnabled()2724     public boolean isSatelliteBeingEnabled() {
2725         if (mSatelliteSessionController != null
2726                 && mSatelliteSessionController.isInEnablingState()) {
2727             return true;
2728         }
2729 
2730         synchronized (mSatelliteEnabledRequestLock) {
2731             return (mSatelliteEnabledRequest != null);
2732         }
2733     }
2734 
2735     /**
2736      * Get whether the satellite modem is enabled or being enabled.
2737      * This will return the cached value instead of querying the satellite modem.
2738      *
2739      * @return {@code true} if the satellite modem is enabled or being enabled, {@code false}
2740      * otherwise.
2741      */
isSatelliteEnabledOrBeingEnabled()2742     public boolean isSatelliteEnabledOrBeingEnabled() {
2743         return isSatelliteEnabled() || isSatelliteBeingEnabled();
2744     }
2745 
2746     /**
2747      * Get whether satellite modem is being disabled.
2748      *
2749      * @return {@code true} if the satellite modem is being disabled and {@code false} otherwise.
2750      */
isSatelliteBeingDisabled()2751     public boolean isSatelliteBeingDisabled() {
2752         if (mSatelliteSessionController != null
2753                 && mSatelliteSessionController.isInDisablingState()) {
2754             return true;
2755         }
2756 
2757         synchronized (mSatelliteEnabledRequestLock) {
2758             return (mSatelliteDisabledRequest != null);
2759         }
2760     }
2761 
2762     /**
2763      * Request to get whether the satellite service demo mode is enabled.
2764      *
2765      * @param result The result receiver that returns whether the satellite demo mode is enabled
2766      *               if the request is successful or an error code if the request failed.
2767      */
requestIsDemoModeEnabled(@onNull ResultReceiver result)2768     public void requestIsDemoModeEnabled(@NonNull ResultReceiver result) {
2769         int error = evaluateOemSatelliteRequestAllowed(true);
2770         if (error != SATELLITE_RESULT_SUCCESS) {
2771             result.send(error, null);
2772             return;
2773         }
2774 
2775         final Bundle bundle = new Bundle();
2776         bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled);
2777         result.send(SATELLITE_RESULT_SUCCESS, bundle);
2778     }
2779 
2780     /**
2781      * Get whether the satellite service demo mode is enabled.
2782      *
2783      * @return {@code true} if the satellite demo mode is enabled and {@code false} otherwise.
2784      */
isDemoModeEnabled()2785     public boolean isDemoModeEnabled() {
2786         return mIsDemoModeEnabled;
2787     }
2788 
2789     /**
2790      * Request to get whether the satellite enabled request is for emergency or not.
2791      *
2792      * @param result The result receiver that returns whether the request is for emergency
2793      *               if the request is successful or an error code if the request failed.
2794      */
requestIsEmergencyModeEnabled(@onNull ResultReceiver result)2795     public void requestIsEmergencyModeEnabled(@NonNull ResultReceiver result) {
2796         synchronized (mSatelliteEnabledRequestLock) {
2797             Bundle bundle = new Bundle();
2798             bundle.putBoolean(SatelliteManager.KEY_EMERGENCY_MODE_ENABLED,
2799                     getRequestIsEmergency());
2800             result.send(SATELLITE_RESULT_SUCCESS, bundle);
2801         }
2802     }
2803 
2804     /**
2805      * Request to get whether the satellite service is supported on the device.
2806      *
2807      * @param result The result receiver that returns whether the satellite service is supported on
2808      *               the device if the request is successful or an error code if the request failed.
2809      */
requestIsSatelliteSupported(@onNull ResultReceiver result)2810     public void requestIsSatelliteSupported(@NonNull ResultReceiver result) {
2811         int subId = getSelectedSatelliteSubId();
2812         Boolean isSatelliteSupported = getIsSatelliteSupported();
2813         if (isSatelliteSupported != null) {
2814             /* We have already successfully queried the satellite modem. */
2815             Bundle bundle = new Bundle();
2816             bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, isSatelliteSupported);
2817             bundle.putInt(SATELLITE_SUBSCRIPTION_ID, subId);
2818             result.send(SATELLITE_RESULT_SUCCESS, bundle);
2819             return;
2820         }
2821 
2822         sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, null);
2823     }
2824 
2825     /**
2826      * Request to get the {@link SatelliteCapabilities} of the satellite service.
2827      *
2828      * @param result The result receiver that returns the {@link SatelliteCapabilities}
2829      *               if the request is successful or an error code if the request failed.
2830      */
requestSatelliteCapabilities(@onNull ResultReceiver result)2831     public void requestSatelliteCapabilities(@NonNull ResultReceiver result) {
2832         int error = evaluateOemSatelliteRequestAllowed(false);
2833         if (error != SATELLITE_RESULT_SUCCESS) {
2834             result.send(error, null);
2835             return;
2836         }
2837 
2838         if (getSatelliteCapabilities() != null) {
2839             Bundle bundle = new Bundle();
2840             overrideSatelliteCapabilitiesIfApplicable();
2841             bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
2842                     getSatelliteCapabilities());
2843             result.send(SATELLITE_RESULT_SUCCESS, bundle);
2844             return;
2845         }
2846 
2847         sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, null);
2848     }
2849 
2850     /**
2851      * Start receiving satellite transmission updates.
2852      * This can be called by the pointing UI when the user starts pointing to the satellite.
2853      * Modem should continue to report the pointing input as the device or satellite moves.
2854      *
2855      * @param errorCallback The callback to get the error code of the request.
2856      * @param callback The callback to notify of satellite transmission updates.
2857      */
startSatelliteTransmissionUpdates( @onNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)2858     public void startSatelliteTransmissionUpdates(
2859             @NonNull IIntegerConsumer errorCallback,
2860             @NonNull ISatelliteTransmissionUpdateCallback callback) {
2861         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
2862         int error = evaluateOemSatelliteRequestAllowed(true);
2863         if (error != SATELLITE_RESULT_SUCCESS) {
2864             result.accept(error);
2865             return;
2866         }
2867 
2868         final int validSubId = getSelectedSatelliteSubId();
2869         mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback);
2870         sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES,
2871                 new SatelliteTransmissionUpdateArgument(result, callback, validSubId), null);
2872     }
2873 
2874     /**
2875      * Stop receiving satellite transmission updates.
2876      * This can be called by the pointing UI when the user stops pointing to the satellite.
2877      *
2878      * @param errorCallback The callback to get the error code of the request.
2879      * @param callback The callback that was passed to {@link #startSatelliteTransmissionUpdates(
2880      *                 int, IIntegerConsumer, ISatelliteTransmissionUpdateCallback)}.
2881      */
stopSatelliteTransmissionUpdates(@onNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)2882     public void stopSatelliteTransmissionUpdates(@NonNull IIntegerConsumer errorCallback,
2883             @NonNull ISatelliteTransmissionUpdateCallback callback) {
2884         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
2885         mPointingAppController.unregisterForSatelliteTransmissionUpdates(
2886                 getSelectedSatelliteSubId(), result, callback);
2887 
2888         // Even if handler is null - which means there are no listeners, the modem command to stop
2889         // satellite transmission updates might have failed. The callers might want to retry
2890         // sending the command. Thus, we always need to send this command to the modem.
2891         sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, null);
2892     }
2893 
2894     /**
2895      * Register the subscription with a satellite provider.
2896      * This is needed to register the subscription if the provider allows dynamic registration.
2897      *
2898      * @param token The token to be used as a unique identifier for provisioning with satellite
2899      *              gateway.
2900      * @param provisionData Data from the provisioning app that can be used by provisioning server
2901      * @param callback The callback to get the error code of the request.
2902      *
2903      * @return The signal transport used by the caller to cancel the provision request,
2904      *         or {@code null} if the request failed.
2905      */
provisionSatelliteService( @onNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer callback)2906     @Nullable public ICancellationSignal provisionSatelliteService(
2907             @NonNull String token, @NonNull byte[] provisionData,
2908             @NonNull IIntegerConsumer callback) {
2909         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2910         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
2911             List<SatelliteSubscriberInfo> subscriberInfoList =
2912                     getNtnOnlySatelliteSubscriberInfoList(result);
2913             if (subscriberInfoList == null) {
2914                 return null;
2915             }
2916             ResultReceiver internalReceiver = new ResultReceiver(this) {
2917                 @Override
2918                 protected void onReceiveResult(int resultCode, Bundle resultData) {
2919                     plogd("provisionSatelliteService: resultCode=" + resultCode
2920                               + ", resultData=" + resultData);
2921                     result.accept(resultCode);
2922                 }
2923             };
2924             provisionSatellite(subscriberInfoList, internalReceiver);
2925 
2926             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
2927             CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> {
2928                 deprovisionSatellite(subscriberInfoList, internalReceiver);
2929                 mProvisionMetricsStats.setIsCanceled(true);
2930             });
2931             return cancelTransport;
2932         } else {
2933             int error = evaluateOemSatelliteRequestAllowed(false);
2934             if (error != SATELLITE_RESULT_SUCCESS) {
2935                 result.accept(error);
2936                 return null;
2937             }
2938 
2939             final int validSubId = getSelectedSatelliteSubId();
2940             if (mSatelliteProvisionCallbacks.containsKey(validSubId)) {
2941                 result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS);
2942                 return null;
2943             }
2944 
2945             Boolean satelliteProvisioned = isDeviceProvisioned();
2946             if (satelliteProvisioned != null && satelliteProvisioned) {
2947                 result.accept(SATELLITE_RESULT_SUCCESS);
2948                 return null;
2949             }
2950 
2951             sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE,
2952                     new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId),
2953                     null);
2954 
2955             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
2956             CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> {
2957                 sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
2958                         new ProvisionSatelliteServiceArgument(token, provisionData, null,
2959                                 validSubId), null);
2960                 mProvisionMetricsStats.setIsCanceled(true);
2961             });
2962             return cancelTransport;
2963         }
2964     }
2965 
2966     /**
2967      * Unregister the device/subscription with the satellite provider.
2968      * This is needed if the provider allows dynamic registration. Once deprovisioned,
2969      * {@link android.telephony.satellite.SatelliteProvisionStateCallback
2970      * #onSatelliteProvisionStateChanged(boolean)}
2971      * should report as deprovisioned.
2972      *
2973      * @param token The token of the device/subscription to be deprovisioned.
2974      * @param callback The callback to get the error code of the request.
2975      */
deprovisionSatelliteService( @onNull String token, @NonNull IIntegerConsumer callback)2976     public void deprovisionSatelliteService(
2977             @NonNull String token, @NonNull IIntegerConsumer callback) {
2978         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2979         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
2980             List<SatelliteSubscriberInfo> subscriberInfoList =
2981                     getNtnOnlySatelliteSubscriberInfoList(result);
2982             if (subscriberInfoList == null) {
2983                 return;
2984             }
2985             ResultReceiver internalReceiver = new ResultReceiver(this) {
2986                 @Override
2987                 protected void onReceiveResult(int resultCode, Bundle resultData) {
2988                     plogd("deprovisionSatelliteService: resultCode=" + resultCode
2989                               + ", resultData=" + resultData);
2990                     result.accept(resultCode);
2991                 }
2992             };
2993             deprovisionSatellite(subscriberInfoList, internalReceiver);
2994         } else {
2995             int error = evaluateOemSatelliteRequestAllowed(false);
2996             if (error != SATELLITE_RESULT_SUCCESS) {
2997                 result.accept(error);
2998                 return;
2999             }
3000 
3001             if (Boolean.FALSE.equals(isDeviceProvisioned())) {
3002                 result.accept(SATELLITE_RESULT_SUCCESS);
3003                 return;
3004             }
3005 
3006             sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
3007                 new ProvisionSatelliteServiceArgument(token, null,
3008                         result, getSelectedSatelliteSubId()),
3009                 null);
3010         }
3011     }
3012 
3013     /**
3014      * Registers for the satellite provision state changed.
3015      *
3016      * @param callback The callback to handle the satellite provision state changed event.
3017      *
3018      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3019      */
registerForSatelliteProvisionStateChanged( @onNull ISatelliteProvisionStateCallback callback)3020     @SatelliteManager.SatelliteResult public int registerForSatelliteProvisionStateChanged(
3021             @NonNull ISatelliteProvisionStateCallback callback) {
3022         mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback);
3023 
3024         boolean isProvisioned = Boolean.TRUE.equals(isDeviceProvisioned());
3025         try {
3026             callback.onSatelliteProvisionStateChanged(isProvisioned);
3027         } catch (RemoteException ex) {
3028             loge("registerForSatelliteProvisionStateChanged: " + ex);
3029         }
3030         synchronized (mDeviceProvisionLock) {
3031             plogd("registerForSatelliteProvisionStateChanged: report current provisioned "
3032                     + "state, state=" + isProvisioned);
3033         }
3034 
3035         return SATELLITE_RESULT_SUCCESS;
3036     }
3037 
3038     /**
3039      * Unregisters for the satellite provision state changed.
3040      * If callback was not registered before, the request will be ignored.
3041      *
3042      * @param callback The callback that was passed to
3043      * {@link #registerForSatelliteProvisionStateChanged(int, ISatelliteProvisionStateCallback)}.
3044      */
unregisterForSatelliteProvisionStateChanged( @onNull ISatelliteProvisionStateCallback callback)3045     public void unregisterForSatelliteProvisionStateChanged(
3046             @NonNull ISatelliteProvisionStateCallback callback) {
3047         mSatelliteProvisionStateChangedListeners.remove(callback.asBinder());
3048     }
3049 
3050     /**
3051      * Request to get whether the device is provisioned with a satellite provider.
3052      *
3053      * @param result The result receiver that returns whether the device is provisioned with a
3054      *               satellite provider if the request is successful or an error code if the
3055      *               request failed.
3056      */
requestIsSatelliteProvisioned(@onNull ResultReceiver result)3057     public void requestIsSatelliteProvisioned(@NonNull ResultReceiver result) {
3058         int error = evaluateOemSatelliteRequestAllowed(false);
3059         if (error != SATELLITE_RESULT_SUCCESS) {
3060             result.send(error, null);
3061             return;
3062         }
3063 
3064         synchronized (mDeviceProvisionLock) {
3065             if (mIsDeviceProvisioned != null) {
3066                 Bundle bundle = new Bundle();
3067                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED,
3068                         mIsDeviceProvisioned);
3069                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
3070                 return;
3071             }
3072         }
3073 
3074         sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, null);
3075         incrementResultReceiverCount("SC:requestIsSatelliteProvisioned");
3076     }
3077 
3078     /**
3079      * Registers for modem state changed from satellite modem.
3080      *
3081      * @param callback The callback to handle the satellite modem state changed event.
3082      *
3083      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3084      */
registerForSatelliteModemStateChanged( @onNull ISatelliteModemStateCallback callback)3085     @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(
3086             @NonNull ISatelliteModemStateCallback callback) {
3087         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
3088             plogd("registerForSatelliteModemStateChanged: add Listeners for ModemState");
3089             mSatelliteRegistrationFailureListeners.put(callback.asBinder(), callback);
3090             mTerrestrialNetworkAvailableChangedListeners.put(callback.asBinder(), callback);
3091         }
3092         if (mSatelliteSessionController != null) {
3093             mSatelliteSessionController.registerForSatelliteModemStateChanged(callback);
3094         } else {
3095             ploge("registerForSatelliteModemStateChanged: mSatelliteSessionController"
3096                     + " is not initialized yet");
3097             return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
3098         }
3099         return SATELLITE_RESULT_SUCCESS;
3100     }
3101 
3102     /**
3103      * Unregisters for modem state changed from satellite modem.
3104      * If callback was not registered before, the request will be ignored.
3105      *
3106      * @param callback The callback that was passed to
3107      * {@link #registerForSatelliteModemStateChanged(int, ISatelliteModemStateCallback)}.
3108      */
unregisterForModemStateChanged( @onNull ISatelliteModemStateCallback callback)3109     public void unregisterForModemStateChanged(
3110             @NonNull ISatelliteModemStateCallback callback) {
3111         if (mSatelliteSessionController != null) {
3112             mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback);
3113         } else {
3114             ploge("unregisterForModemStateChanged: mSatelliteSessionController"
3115                     + " is not initialized yet");
3116         }
3117         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
3118             plogd("unregisterForModemStateChanged: remove Listeners for ModemState");
3119             mSatelliteRegistrationFailureListeners.remove(callback.asBinder());
3120             mTerrestrialNetworkAvailableChangedListeners.remove(callback.asBinder());
3121         }
3122     }
3123 
3124     /**
3125      * Register to receive incoming datagrams over satellite.
3126      *
3127      * @param callback The callback to handle incoming datagrams over satellite.
3128      *
3129      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3130      */
registerForIncomingDatagram( @onNull ISatelliteDatagramCallback callback)3131     @SatelliteManager.SatelliteResult public int registerForIncomingDatagram(
3132             @NonNull ISatelliteDatagramCallback callback) {
3133         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
3134             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
3135         }
3136         plogd("registerForIncomingDatagram: callback=" + callback);
3137         return mDatagramController.registerForSatelliteDatagram(
3138                 getSelectedSatelliteSubId(), callback);
3139     }
3140 
3141     /**
3142      * Unregister to stop receiving incoming datagrams over satellite.
3143      * If callback was not registered before, the request will be ignored.
3144      *
3145      * @param callback The callback that was passed to
3146      *                 {@link #registerForIncomingDatagram(int, ISatelliteDatagramCallback)}.
3147      */
unregisterForIncomingDatagram( @onNull ISatelliteDatagramCallback callback)3148     public void unregisterForIncomingDatagram(
3149             @NonNull ISatelliteDatagramCallback callback) {
3150         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
3151             return;
3152         }
3153         plogd("unregisterForIncomingDatagram: callback=" + callback);
3154         mDatagramController.unregisterForSatelliteDatagram(
3155                 getSelectedSatelliteSubId(), callback);
3156     }
3157 
3158     /**
3159      * Poll pending satellite datagrams over satellite.
3160      *
3161      * This method requests modem to check if there are any pending datagrams to be received over
3162      * satellite. If there are any incoming datagrams, they will be received via
3163      * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived(
3164      * long, SatelliteDatagram, int, Consumer)}
3165      *
3166      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
3167      */
pollPendingDatagrams(@onNull IIntegerConsumer callback)3168     public void pollPendingDatagrams(@NonNull IIntegerConsumer callback) {
3169         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
3170         int error = evaluateOemSatelliteRequestAllowed(true);
3171         if (error != SATELLITE_RESULT_SUCCESS) {
3172             result.accept(error);
3173             return;
3174         }
3175 
3176         mDatagramController.pollPendingSatelliteDatagrams(
3177                 getSelectedSatelliteSubId(), result);
3178     }
3179 
3180     /**
3181      * Send datagram over satellite.
3182      *
3183      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
3184      * input to this method. Datagram received here will be passed down to modem without any
3185      * encoding or encryption.
3186      *
3187      * @param datagramType datagram type indicating whether the datagram is of type
3188      *                     SOS_SMS or LOCATION_SHARING.
3189      * @param datagram encoded gateway datagram which is encrypted by the caller.
3190      *                 Datagram will be passed down to modem without any encoding or encryption.
3191      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
3192      *                                 full screen mode.
3193      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
3194      */
sendDatagram(@atelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull IIntegerConsumer callback)3195     public void sendDatagram(@SatelliteManager.DatagramType int datagramType,
3196             SatelliteDatagram datagram, boolean needFullScreenPointingUI,
3197             @NonNull IIntegerConsumer callback) {
3198         plogd("sendSatelliteDatagram: datagramType: " + datagramType
3199                 + " needFullScreenPointingUI: " + needFullScreenPointingUI);
3200 
3201         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
3202         int error = evaluateOemSatelliteRequestAllowed(true);
3203         if (error != SATELLITE_RESULT_SUCCESS) {
3204             result.accept(error);
3205             return;
3206         }
3207 
3208         /**
3209          * TODO for NTN-based satellites: Check if satellite is acquired.
3210          */
3211         if (mNeedsSatellitePointing) {
3212 
3213             mPointingAppController.startPointingUI(needFullScreenPointingUI, mIsDemoModeEnabled,
3214                     mIsEmergency);
3215         }
3216 
3217         mDatagramController.sendSatelliteDatagram(getSelectedSatelliteSubId(), datagramType,
3218                 datagram, needFullScreenPointingUI, result);
3219     }
3220 
3221     /**
3222      * Request to get the time after which the satellite will be visible.
3223      *
3224      * @param result The result receiver that returns the time after which the satellite will
3225      *               be visible if the request is successful or an error code if the request failed.
3226      */
requestTimeForNextSatelliteVisibility(@onNull ResultReceiver result)3227     public void requestTimeForNextSatelliteVisibility(@NonNull ResultReceiver result) {
3228         int error = evaluateOemSatelliteRequestAllowed(true);
3229         if (error != SATELLITE_RESULT_SUCCESS) {
3230             result.send(error, null);
3231             return;
3232         }
3233 
3234         sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, null);
3235         incrementResultReceiverCount("SC:requestTimeForNextSatelliteVisibility");
3236     }
3237 
3238     /**
3239      * Inform whether the device is aligned with the satellite in both real and demo mode.
3240      *
3241      * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}.
3242      */
setDeviceAlignedWithSatellite(@onNull boolean isAligned)3243     public void setDeviceAlignedWithSatellite(@NonNull boolean isAligned) {
3244         DemoSimulator.getInstance().setDeviceAlignedWithSatellite(isAligned);
3245         mDatagramController.setDeviceAlignedWithSatellite(isAligned);
3246         if (mSatelliteSessionController != null) {
3247             mSatelliteSessionController.setDeviceAlignedWithSatellite(isAligned);
3248         } else {
3249             ploge("setDeviceAlignedWithSatellite: mSatelliteSessionController"
3250                     + " is not initialized yet");
3251         }
3252     }
3253 
3254     /**
3255      * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
3256      * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled,
3257      * and request modem to enable/disable satellite accordingly if the desired state does not match
3258      * the current state.
3259      *
3260      * @param subId The subId of the subscription to request for.
3261      * @param reason Reason for disallowing satellite communication for carrier.
3262      * @param callback The callback to get the result of the request.
3263      */
addAttachRestrictionForCarrier(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, @NonNull IIntegerConsumer callback)3264     public void addAttachRestrictionForCarrier(int subId,
3265             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
3266             @NonNull IIntegerConsumer callback) {
3267         logd("addAttachRestrictionForCarrier(" + subId + ", " + reason + ")");
3268         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
3269 
3270         synchronized (mIsSatelliteEnabledLock) {
3271             if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault(
3272                     subId, Collections.emptySet()).isEmpty()) {
3273                 mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>());
3274             } else if (mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
3275                 result.accept(SATELLITE_RESULT_SUCCESS);
3276                 return;
3277             }
3278             mSatelliteAttachRestrictionForCarrierArray.get(subId).add(reason);
3279         }
3280         RequestHandleSatelliteAttachRestrictionForCarrierArgument request =
3281                 new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason,
3282                         result);
3283         sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request,
3284                 SatelliteServiceUtils.getPhone(subId));
3285     }
3286 
3287     /**
3288      * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
3289      * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled,
3290      * and request modem to enable/disable satellite accordingly if the desired state does not match
3291      * the current state.
3292      *
3293      * @param subId The subId of the subscription to request for.
3294      * @param reason Reason for disallowing satellite communication.
3295      * @param callback The callback to get the result of the request.
3296      */
removeAttachRestrictionForCarrier(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, @NonNull IIntegerConsumer callback)3297     public void removeAttachRestrictionForCarrier(int subId,
3298             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
3299             @NonNull IIntegerConsumer callback) {
3300         logd("removeAttachRestrictionForCarrier(" + subId + ", " + reason + ")");
3301         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
3302 
3303         synchronized (mIsSatelliteEnabledLock) {
3304             if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault(
3305                     subId, Collections.emptySet()).isEmpty()
3306                     || !mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
3307                 result.accept(SATELLITE_RESULT_SUCCESS);
3308                 return;
3309             }
3310             mSatelliteAttachRestrictionForCarrierArray.get(subId).remove(reason);
3311         }
3312         RequestHandleSatelliteAttachRestrictionForCarrierArgument request =
3313                 new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason,
3314                         result);
3315         sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request,
3316                 SatelliteServiceUtils.getPhone(subId));
3317     }
3318 
3319     /**
3320      * Get reasons for disallowing satellite communication, as requested by
3321      * {@link #addAttachRestrictionForCarrier(int, int, IIntegerConsumer)}.
3322      *
3323      * @param subId The subId of the subscription to request for.
3324      *
3325      * @return Set of reasons for disallowing satellite attach for carrier.
3326      */
getAttachRestrictionReasonsForCarrier(int subId)3327     @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
3328         synchronized (mIsSatelliteEnabledLock) {
3329             Set<Integer> resultSet =
3330                     mSatelliteAttachRestrictionForCarrierArray.get(subId);
3331             if (resultSet == null) {
3332                 return new HashSet<>();
3333             }
3334             return new HashSet<>(resultSet);
3335         }
3336     }
3337 
3338     /**
3339      * Request to get the signal strength of the satellite connection.
3340      *
3341      * @param result Result receiver to get the error code of the request and the current signal
3342      * strength of the satellite connection.
3343      */
requestNtnSignalStrength(@onNull ResultReceiver result)3344     public void requestNtnSignalStrength(@NonNull ResultReceiver result) {
3345         if (DBG) plogd("requestNtnSignalStrength()");
3346 
3347         int error = evaluateOemSatelliteRequestAllowed(true);
3348         if (error != SATELLITE_RESULT_SUCCESS) {
3349             result.send(error, null);
3350             return;
3351         }
3352 
3353         /* In case cache is available, it is not needed to request non-terrestrial signal strength
3354         to modem */
3355         synchronized (mNtnSignalsStrengthLock) {
3356             if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
3357                 Bundle bundle = new Bundle();
3358                 bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, mNtnSignalStrength);
3359                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
3360                 return;
3361             }
3362         }
3363 
3364         Phone phone = SatelliteServiceUtils.getPhone();
3365         sendRequestAsync(CMD_REQUEST_NTN_SIGNAL_STRENGTH, result, phone);
3366         incrementResultReceiverCount("SC:requestNtnSignalStrength");
3367     }
3368 
3369     /**
3370      * Registers for NTN signal strength changed from satellite modem. If the registration operation
3371      * is not successful, a {@link ServiceSpecificException} that contains
3372      * {@link SatelliteManager.SatelliteResult} will be thrown.
3373      *
3374      * @param callback The callback to handle the NTN signal strength changed event. If the
3375      * operation is successful, {@link INtnSignalStrengthCallback#onNtnSignalStrengthChanged(
3376      * NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of
3377      * {@link NtnSignalStrength.NtnSignalStrengthLevel} when the signal strength of non-terrestrial
3378      * network has changed.
3379      *
3380      * @throws ServiceSpecificException If the callback registration operation fails.
3381      */
registerForNtnSignalStrengthChanged( @onNull INtnSignalStrengthCallback callback)3382     public void registerForNtnSignalStrengthChanged(
3383             @NonNull INtnSignalStrengthCallback callback) throws RemoteException {
3384         if (DBG) plogd("registerForNtnSignalStrengthChanged()");
3385 
3386         int error = evaluateOemSatelliteRequestAllowed(false);
3387         if (error == SATELLITE_RESULT_SUCCESS) {
3388             mNtnSignalStrengthChangedListeners.put(callback.asBinder(), callback);
3389             synchronized (mNtnSignalsStrengthLock) {
3390                 try {
3391                     callback.onNtnSignalStrengthChanged(mNtnSignalStrength);
3392                     plogd("registerForNtnSignalStrengthChanged: " + mNtnSignalStrength);
3393                 } catch (RemoteException ex) {
3394                     ploge("registerForNtnSignalStrengthChanged: RemoteException ex="
3395                             + ex);
3396                 }
3397             }
3398         } else {
3399             throw new RemoteException(new IllegalStateException("registration fails: " + error));
3400         }
3401     }
3402 
3403     /**
3404      * Unregisters for NTN signal strength changed from satellite modem.
3405      * If callback was not registered before, the request will be ignored.
3406      *
3407      * changed event.
3408      * @param callback The callback that was passed to
3409      * {@link #registerForNtnSignalStrengthChanged(int, INtnSignalStrengthCallback)}
3410      */
unregisterForNtnSignalStrengthChanged( @onNull INtnSignalStrengthCallback callback)3411     public void unregisterForNtnSignalStrengthChanged(
3412             @NonNull INtnSignalStrengthCallback callback) {
3413         if (DBG) plogd("unregisterForNtnSignalStrengthChanged()");
3414         mNtnSignalStrengthChangedListeners.remove(callback.asBinder());
3415     }
3416 
3417     /**
3418      * Registers for satellite capabilities change event from the satellite service.
3419      *
3420      * @param callback The callback to handle the satellite capabilities changed event.
3421      *
3422      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3423      */
registerForCapabilitiesChanged( @onNull ISatelliteCapabilitiesCallback callback)3424     @SatelliteManager.SatelliteResult public int registerForCapabilitiesChanged(
3425             @NonNull ISatelliteCapabilitiesCallback callback) {
3426         if (DBG) plogd("registerForCapabilitiesChanged()");
3427 
3428         int error = evaluateOemSatelliteRequestAllowed(false);
3429         if (error != SATELLITE_RESULT_SUCCESS) return error;
3430 
3431         mSatelliteCapabilitiesChangedListeners.put(callback.asBinder(), callback);
3432         return SATELLITE_RESULT_SUCCESS;
3433     }
3434 
3435     /**
3436      * Unregisters for satellite capabilities change event from the satellite service.
3437      * If callback was not registered before, the request will be ignored.
3438      *
3439      * changed event.
3440      * @param callback The callback that was passed to
3441      * {@link #registerForCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)}
3442      */
unregisterForCapabilitiesChanged( @onNull ISatelliteCapabilitiesCallback callback)3443     public void unregisterForCapabilitiesChanged(
3444             @NonNull ISatelliteCapabilitiesCallback callback) {
3445         if (DBG) plogd("unregisterForCapabilitiesChanged()");
3446         mSatelliteCapabilitiesChangedListeners.remove(callback.asBinder());
3447     }
3448 
3449     /**
3450      * Registers for the satellite supported state changed.
3451      *
3452      * @param callback The callback to handle the satellite supported state changed event.
3453      *
3454      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3455      */
registerForSatelliteSupportedStateChanged( @onNull IBooleanConsumer callback)3456     @SatelliteManager.SatelliteResult public int registerForSatelliteSupportedStateChanged(
3457             @NonNull IBooleanConsumer callback) {
3458         mSatelliteSupportedStateChangedListeners.put(callback.asBinder(), callback);
3459         return SATELLITE_RESULT_SUCCESS;
3460     }
3461 
3462     /**
3463      * Unregisters for the satellite supported state changed.
3464      * If callback was not registered before, the request will be ignored.
3465      *
3466      * @param callback The callback that was passed to
3467      *                 {@link #registerForSatelliteSupportedStateChanged(IBooleanConsumer)}
3468      */
unregisterForSatelliteSupportedStateChanged( @onNull IBooleanConsumer callback)3469     public void unregisterForSatelliteSupportedStateChanged(
3470             @NonNull IBooleanConsumer callback) {
3471         mSatelliteSupportedStateChangedListeners.remove(callback.asBinder());
3472     }
3473 
3474     /**
3475      * Registers for selected satellite subscription changed event.
3476      *
3477      * @param callback The callback to handle the selected satellite subscription changed event.
3478      *
3479      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
3480      */
3481     @SatelliteManager.SatelliteResult
registerForSelectedNbIotSatelliteSubscriptionChanged( @onNull ISelectedNbIotSatelliteSubscriptionCallback callback)3482     public int registerForSelectedNbIotSatelliteSubscriptionChanged(
3483             @NonNull ISelectedNbIotSatelliteSubscriptionCallback callback) {
3484         if (DBG) plogd("registerForSelectedNbIotSatelliteSubscriptionChanged()");
3485 
3486         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
3487             plogd("carrierRoamingNbIotNtn flag is disabled");
3488             return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
3489         }
3490 
3491         int error = evaluateOemSatelliteRequestAllowed(false);
3492         if (error != SATELLITE_RESULT_SUCCESS) return error;
3493 
3494         mSelectedNbIotSatelliteSubscriptionChangedListeners.put(callback.asBinder(), callback);
3495         try {
3496             callback.onSelectedNbIotSatelliteSubscriptionChanged(getSelectedSatelliteSubId());
3497         } catch (RemoteException ex) {
3498             ploge("registerForSelectedNbIotSatelliteSubscriptionChanged: RemoteException ex="
3499                     + ex);
3500         }
3501         return SATELLITE_RESULT_SUCCESS;
3502     }
3503 
3504     /**
3505      * Unregisters for the selected satellite subscription changed event.
3506      * If callback was not registered before, the request will be ignored.
3507      *
3508      * @param callback The callback that was passed to {@link
3509      *     #registerForSelectedNbIotSatelliteSubscriptionChanged(
3510      *     ISelectedNbIotSatelliteSubscriptionCallback)}.
3511      */
unregisterForSelectedNbIotSatelliteSubscriptionChanged( @onNull ISelectedNbIotSatelliteSubscriptionCallback callback)3512     public void unregisterForSelectedNbIotSatelliteSubscriptionChanged(
3513             @NonNull ISelectedNbIotSatelliteSubscriptionCallback callback) {
3514         if (DBG) plogd("unregisterForSelectedNbIotSatelliteSubscriptionChanged()");
3515 
3516         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
3517             plogd("carrierRoamingNbIotNtn flag is disabled");
3518             return;
3519         }
3520 
3521         int error = evaluateOemSatelliteRequestAllowed(true);
3522         if (error == SATELLITE_RESULT_SUCCESS) {
3523             mSelectedNbIotSatelliteSubscriptionChangedListeners.remove(callback.asBinder());
3524         }
3525     }
3526 
3527     /**
3528      * This API can be used by only CTS to update satellite vendor service package name.
3529      *
3530      * @param servicePackageName The package name of the satellite vendor service.
3531      * @param provisioned          Whether satellite should be provisioned or not.
3532      * @return {@code true} if the satellite vendor service is set successfully,
3533      * {@code false} otherwise.
3534      */
setSatelliteServicePackageName(@ullable String servicePackageName, String provisioned)3535     public boolean setSatelliteServicePackageName(@Nullable String servicePackageName,
3536             String provisioned) {
3537         if (!isMockModemAllowed()) {
3538             plogd("setSatelliteServicePackageName: mock modem not allowed");
3539             return false;
3540         }
3541 
3542         // Cached states need to be cleared whenever switching satellite vendor services.
3543         plogd("setSatelliteServicePackageName: Resetting cached states, provisioned="
3544                 + provisioned);
3545         synchronized (mIsSatelliteSupportedLock) {
3546             mIsSatelliteSupported = null;
3547         }
3548         synchronized (mIsSatelliteEnabledLock) {
3549             mIsSatelliteEnabled = null;
3550         }
3551         synchronized (mSatelliteCapabilitiesLock) {
3552             mSatelliteCapabilities = null;
3553         }
3554         mSatelliteModemInterface.setSatelliteServicePackageName(servicePackageName);
3555         return true;
3556     }
3557 
3558     /**
3559      * This API can be used by only CTS to update the timeout duration in milliseconds that
3560      * satellite should stay at listening mode to wait for the next incoming page before disabling
3561      * listening mode.
3562      *
3563      * @param timeoutMillis The timeout duration in millisecond.
3564      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
3565      */
setSatelliteListeningTimeoutDuration(long timeoutMillis)3566     public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
3567         if (mSatelliteSessionController == null) {
3568             ploge("mSatelliteSessionController is not initialized yet");
3569             return false;
3570         }
3571         return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis);
3572     }
3573 
3574     /**
3575      * This API can be used by only CTS to override TN scanning support.
3576      *
3577      * @param concurrentTnScanningSupported Whether concurrent TN scanning is supported.
3578      * @param tnScanningDuringSatelliteSessionAllowed Whether TN scanning is allowed during
3579      * a satellite session.
3580      * @return {@code true} if the TN scanning support is set successfully,
3581      * {@code false} otherwise.
3582      */
setTnScanningSupport(boolean reset, boolean concurrentTnScanningSupported, boolean tnScanningDuringSatelliteSessionAllowed)3583     public boolean setTnScanningSupport(boolean reset, boolean concurrentTnScanningSupported,
3584         boolean tnScanningDuringSatelliteSessionAllowed) {
3585         if (mSatelliteSessionController == null) {
3586             ploge("setTnScanningSupport: mSatelliteSessionController is not initialized yet");
3587             return false;
3588         }
3589         return mSatelliteSessionController.setTnScanningSupport(reset,
3590                 concurrentTnScanningSupported, tnScanningDuringSatelliteSessionAllowed);
3591     }
3592 
3593     /**
3594      * This API can be used by only CTS to control ingoring cellular service state event.
3595      *
3596      * @param enabled Whether to enable boolean config.
3597      * @return {@code true} if the value is set successfully, {@code false} otherwise.
3598      */
setSatelliteIgnoreCellularServiceState(boolean enabled)3599     public boolean setSatelliteIgnoreCellularServiceState(boolean enabled) {
3600         plogd("setSatelliteIgnoreCellularServiceState - " + enabled);
3601         if (mSatelliteSessionController == null) {
3602             ploge("setSatelliteIgnoreCellularServiceState is not initialized yet");
3603             return false;
3604         }
3605         return mSatelliteSessionController.setSatelliteIgnoreCellularServiceState(enabled);
3606     }
3607 
3608     /**
3609      * This API can be used by only CTS to control the feature
3610      * {@code config_support_disable_satellite_while_enable_in_progress}.
3611      *
3612      * @param reset Whether to reset the override.
3613      * @param supported Whether to support the feature.
3614      * @return {@code true} if the value is set successfully, {@code false} otherwise.
3615      */
setSupportDisableSatelliteWhileEnableInProgress( boolean reset, boolean supported)3616     public boolean setSupportDisableSatelliteWhileEnableInProgress(
3617         boolean reset, boolean supported) {
3618         if (!isMockModemAllowed()) {
3619             plogd("setSupportDisableSatelliteWhileEnableInProgress: mock modem not allowed");
3620             return false;
3621         }
3622 
3623         plogd("setSupportDisableSatelliteWhileEnableInProgress - reset=" + reset
3624                   + ", supported=" + supported);
3625         if (reset) {
3626             mOverriddenDisableSatelliteWhileEnableInProgressSupported = null;
3627         } else {
3628             mOverriddenDisableSatelliteWhileEnableInProgressSupported = supported;
3629         }
3630         return true;
3631     }
3632 
3633     /**
3634      * This API can be used by only CTS to override timeout durations used by DatagramController
3635      * module.
3636      *
3637      * @param timeoutMillis The timeout duration in millisecond.
3638      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
3639      */
setDatagramControllerTimeoutDuration( boolean reset, int timeoutType, long timeoutMillis)3640     public boolean setDatagramControllerTimeoutDuration(
3641             boolean reset, int timeoutType, long timeoutMillis) {
3642         plogd("setDatagramControllerTimeoutDuration: reset=" + reset + ", timeoutType="
3643                 + timeoutType + ", timeoutMillis=" + timeoutMillis);
3644         return mDatagramController.setDatagramControllerTimeoutDuration(
3645                 reset, timeoutType, timeoutMillis);
3646     }
3647 
3648     /**
3649      * This API can be used by only CTS to override the boolean configs used by the
3650      * DatagramController module.
3651      *
3652      * @param enable Whether to enable or disable boolean config.
3653      * @return {@code true} if the boolean config is set successfully, {@code false} otherwise.
3654      */
setDatagramControllerBooleanConfig( boolean reset, int booleanType, boolean enable)3655     public boolean setDatagramControllerBooleanConfig(
3656             boolean reset, int booleanType, boolean enable) {
3657         logd("setDatagramControllerBooleanConfig: reset=" + reset + ", booleanType="
3658                 + booleanType + ", enable=" + enable);
3659         return mDatagramController.setDatagramControllerBooleanConfig(
3660                 reset, booleanType, enable);
3661     }
3662 
3663     /**
3664      * This API can be used by only CTS to override timeout durations used by SatelliteController
3665      * module.
3666      *
3667      * @param timeoutMillis The timeout duration in millisecond.
3668      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
3669      */
setSatelliteControllerTimeoutDuration( boolean reset, int timeoutType, long timeoutMillis)3670     public boolean setSatelliteControllerTimeoutDuration(
3671             boolean reset, int timeoutType, long timeoutMillis) {
3672         if (!isMockModemAllowed()) {
3673             plogd("setSatelliteControllerTimeoutDuration: mock modem is not allowed");
3674             return false;
3675         }
3676         plogd("setSatelliteControllerTimeoutDuration: reset=" + reset + ", timeoutType="
3677                 + timeoutType + ", timeoutMillis=" + timeoutMillis);
3678         if (timeoutType == TIMEOUT_TYPE_WAIT_FOR_SATELLITE_ENABLING_RESPONSE) {
3679             if (reset) {
3680                 mWaitTimeForSatelliteEnablingResponse =
3681                         getWaitForSatelliteEnablingResponseTimeoutMillis();
3682             } else {
3683                 mWaitTimeForSatelliteEnablingResponse = timeoutMillis;
3684             }
3685             plogd("mWaitTimeForSatelliteEnablingResponse=" + mWaitTimeForSatelliteEnablingResponse);
3686         } else if (timeoutType == TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS) {
3687             if (reset) {
3688                 mDemoPointingAlignedDurationMillis =
3689                         getDemoPointingAlignedDurationMillisFromResources();
3690             } else {
3691                 mDemoPointingAlignedDurationMillis = timeoutMillis;
3692             }
3693         } else if (timeoutType == TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS) {
3694             if (reset) {
3695                 mDemoPointingNotAlignedDurationMillis =
3696                         getDemoPointingNotAlignedDurationMillisFromResources();
3697             } else {
3698                 mDemoPointingNotAlignedDurationMillis = timeoutMillis;
3699             }
3700         } else if (timeoutType
3701                 == TIMEOUT_TYPE_EVALUATE_ESOS_PROFILES_PRIORITIZATION_DURATION_MILLIS) {
3702             if (reset) {
3703                 mEvaluateEsosProfilesPrioritizationDurationMillis =
3704                         getEvaluateEsosProfilesPrioritizationDurationMillis();
3705             } else {
3706                 mEvaluateEsosProfilesPrioritizationDurationMillis = timeoutMillis;
3707             }
3708         } else {
3709             plogw("Invalid timeoutType=" + timeoutType);
3710             return false;
3711         }
3712         return true;
3713     }
3714 
3715     /**
3716      * This API can be used by only CTS to update satellite gateway service package name.
3717      *
3718      * @param servicePackageName The package name of the satellite gateway service.
3719      * @return {@code true} if the satellite gateway service is set successfully,
3720      * {@code false} otherwise.
3721      */
setSatelliteGatewayServicePackageName(@ullable String servicePackageName)3722     public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
3723         if (mSatelliteSessionController == null) {
3724             ploge("mSatelliteSessionController is not initialized yet");
3725             return false;
3726         }
3727         return mSatelliteSessionController.setSatelliteGatewayServicePackageName(
3728                 servicePackageName);
3729     }
3730 
3731     /**
3732      * This API can be used by only CTS to update satellite pointing UI app package and class names.
3733      *
3734      * @param packageName The package name of the satellite pointing UI app.
3735      * @param className The class name of the satellite pointing UI app.
3736      * @return {@code true} if the satellite pointing UI app package and class is set successfully,
3737      * {@code false} otherwise.
3738      */
setSatellitePointingUiClassName( @ullable String packageName, @Nullable String className)3739     public boolean setSatellitePointingUiClassName(
3740             @Nullable String packageName, @Nullable String className) {
3741         return mPointingAppController.setSatellitePointingUiClassName(packageName, className);
3742     }
3743 
3744     /**
3745      * This API can be used in only testing to override connectivity status in monitoring emergency
3746      * calls and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
3747      *
3748      * @param handoverType The type of handover from emergency call to satellite messaging. Use one
3749      *                     of the following values to enable the override:
3750      *                     0 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
3751      *                     1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911
3752      *                     To disable the override, use -1 for handoverType.
3753      * @param delaySeconds The event EVENT_DISPLAY_EMERGENCY_MESSAGE will be sent to Dialer
3754      *                     delaySeconds after the emergency call starts.
3755      * @return {@code true} if the handover type is set successfully, {@code false} otherwise.
3756      */
setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds)3757     public boolean setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds) {
3758         if (!isMockModemAllowed()) {
3759             ploge("setEmergencyCallToSatelliteHandoverType: mock modem not allowed");
3760             return false;
3761         }
3762         if (isHandoverTypeValid(handoverType)) {
3763             mEnforcedEmergencyCallToSatelliteHandoverType = handoverType;
3764             mDelayInSendingEventDisplayEmergencyMessage = delaySeconds > 0 ? delaySeconds : 0;
3765         } else {
3766             mEnforcedEmergencyCallToSatelliteHandoverType =
3767                     INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
3768             mDelayInSendingEventDisplayEmergencyMessage = 0;
3769         }
3770         return true;
3771     }
3772 
3773     /**
3774      * This API can be used in only testing to override oem-enabled satellite provision status.
3775      *
3776      * @param reset {@code true} mean the overriding status should not be used, {@code false}
3777      *              otherwise.
3778      * @param isProvisioned The overriding provision status.
3779      * @return {@code true} if the provision status is set successfully, {@code false} otherwise.
3780      */
setOemEnabledSatelliteProvisionStatus(boolean reset, boolean isProvisioned)3781     public boolean setOemEnabledSatelliteProvisionStatus(boolean reset, boolean isProvisioned) {
3782         if (!isMockModemAllowed()) {
3783             ploge("setOemEnabledSatelliteProvisionStatus: mock modem not allowed");
3784             return false;
3785         }
3786         synchronized (mDeviceProvisionLock) {
3787             if (reset) {
3788                 mOverriddenIsSatelliteViaOemProvisioned = null;
3789             } else {
3790                 mOverriddenIsSatelliteViaOemProvisioned = isProvisioned;
3791             }
3792         }
3793         return true;
3794     }
3795 
3796     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getEnforcedEmergencyCallToSatelliteHandoverType()3797     protected int getEnforcedEmergencyCallToSatelliteHandoverType() {
3798         return mEnforcedEmergencyCallToSatelliteHandoverType;
3799     }
3800 
3801     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDelayInSendingEventDisplayEmergencyMessage()3802     protected int getDelayInSendingEventDisplayEmergencyMessage() {
3803         return mDelayInSendingEventDisplayEmergencyMessage;
3804     }
3805 
isHandoverTypeValid(int handoverType)3806     private boolean isHandoverTypeValid(int handoverType) {
3807         if (handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
3808                 || handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911) {
3809             return true;
3810         }
3811         return false;
3812     }
3813 
3814     /**
3815      * This function is used by {@link SatelliteModemInterface} to notify
3816      * {@link SatelliteController} that the satellite vendor service was just connected.
3817      * <p>
3818      * {@link SatelliteController} will send requests to satellite modem to check whether it support
3819      * satellite and whether it is provisioned. {@link SatelliteController} will use these cached
3820      * values to serve requests from its clients.
3821      * <p>
3822      * Because satellite vendor service might have just come back from a crash, we need to disable
3823      * the satellite modem so that resources will be cleaned up and internal states will be reset.
3824      */
3825     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteServiceConnected()3826     public void onSatelliteServiceConnected() {
3827         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3828             plogd("onSatelliteServiceConnected");
3829             // Vendor service might have just come back from a crash
3830             moveSatelliteToOffStateAndCleanUpResources(SATELLITE_RESULT_MODEM_ERROR);
3831             final String caller = "SC:onSatelliteServiceConnected";
3832             ResultReceiver receiver = new ResultReceiver(this) {
3833                 @Override
3834                 protected void onReceiveResult(
3835                         int resultCode, Bundle resultData) {
3836                     decrementResultReceiverCount(caller);
3837                     plogd("onSatelliteServiceConnected.requestIsSatelliteSupported:"
3838                             + " resultCode=" + resultCode);
3839                 }
3840             };
3841             requestIsSatelliteSupported(receiver);
3842             incrementResultReceiverCount(caller);
3843         } else {
3844             plogd("onSatelliteServiceConnected: Satellite vendor service is not supported."
3845                     + " Ignored the event");
3846         }
3847     }
3848 
3849     /**
3850      * This function is used by {@link com.android.internal.telephony.ServiceStateTracker} to notify
3851      * {@link SatelliteController} that it has received a request to power on or off the cellular
3852      * radio modem.
3853      *
3854      * @param powerOn {@code true} means cellular radio is about to be powered on, {@code false}
3855      *                 means cellular modem is about to be powered off.
3856      */
onSetCellularRadioPowerStateRequested(boolean powerOn)3857     public void onSetCellularRadioPowerStateRequested(boolean powerOn) {
3858         logd("onSetCellularRadioPowerStateRequested: powerOn=" + powerOn);
3859 
3860         synchronized (mIsRadioOnLock) {
3861             mRadioOffRequested = !powerOn;
3862         }
3863         if (powerOn) {
3864             stopWaitForCellularModemOffTimer();
3865         } else {
3866             requestSatelliteEnabled(
3867                     false /* enableSatellite */, false /* enableDemoMode */,
3868                     false /* isEmergency */,
3869                     new IIntegerConsumer.Stub() {
3870                         @Override
3871                         public void accept(int result) {
3872                             plogd("onSetCellularRadioPowerStateRequested: requestSatelliteEnabled"
3873                                     + " result=" + result);
3874                         }
3875                     });
3876             startWaitForCellularModemOffTimer();
3877         }
3878     }
3879 
3880     /**
3881      * This function is used by {@link com.android.internal.telephony.ServiceStateTracker} to notify
3882      * {@link SatelliteController} that the request to power off the cellular radio modem has
3883      * failed.
3884      */
onPowerOffCellularRadioFailed()3885     public void onPowerOffCellularRadioFailed() {
3886         logd("onPowerOffCellularRadioFailed");
3887         synchronized (mIsRadioOnLock) {
3888             mRadioOffRequested = false;
3889             stopWaitForCellularModemOffTimer();
3890         }
3891     }
3892 
3893     /**
3894      * Notify SMS received.
3895      *
3896      * @param subId The subId of the subscription used to receive SMS
3897      */
onSmsReceived(int subId)3898     public void onSmsReceived(int subId) {
3899         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
3900             logd("onSmsReceived: carrierRoamingNbIotNtn is disabled");
3901             return;
3902         }
3903 
3904         if (!isSatelliteEnabled()) {
3905             logd("onSmsReceived: satellite is not enabled");
3906             return;
3907         }
3908 
3909         int satelliteSubId = getSelectedSatelliteSubId();
3910         if (subId != satelliteSubId) {
3911             logd("onSmsReceived: SMS received " + subId
3912                     + ", but not satellite subscription " + satelliteSubId);
3913             return;
3914         }
3915 
3916         if (mDatagramController != null) {
3917             mDatagramController.onSmsReceived(subId);
3918         } else {
3919             logd("onSmsReceived: DatagramController is not initialized");
3920         }
3921 
3922         mControllerMetricsStats.reportIncomingNtnSmsCount(
3923                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
3924     }
3925 
3926     /**
3927      * @return {@code true} if satellite is supported via OEM on the device,
3928      * {@code  false} otherwise.
3929      */
isSatelliteSupportedViaOem()3930     public boolean isSatelliteSupportedViaOem() {
3931         Boolean supported = isSatelliteSupportedViaOemInternal();
3932         return (supported != null ? supported : false);
3933     }
3934 
3935     /**
3936      * @param subId Subscription ID.
3937      * @return The list of satellite PLMNs used for connecting to satellite networks.
3938      */
3939     @NonNull
getSatellitePlmnsForCarrier(int subId)3940     public List<String> getSatellitePlmnsForCarrier(int subId) {
3941         if (!isSatelliteSupportedViaCarrier(subId)) {
3942             logd("Satellite for carrier is not supported.");
3943             return new ArrayList<>();
3944         }
3945 
3946         return getCarrierPlmnList(subId);
3947     }
3948 
3949     /**
3950      *  checks if data service is allowed, to add part of list of services supported by satellite
3951      *  plmn, when data supported mode
3952      *  {@link CarrierConfigManager#KEY_SATELLITE_DATA_SUPPORT_MODE_INT} is restricted mode and no
3953      *  data service is included at allowed service info at the entitlement and when allowed service
3954      *  info field is present at the entitlement.
3955      *
3956      * @param subId subscription id
3957      * @param plmn  The satellite plmn
3958      * @param allowedServiceValues allowed services info supported by entitlement
3959      * @return {@code true} is supports data service else {@code false}
3960      */
isDataServiceUpdateRequired(int subId, String plmn, List<Integer> allowedServiceValues)3961     private boolean isDataServiceUpdateRequired(int subId, String plmn,
3962             List<Integer> allowedServiceValues) {
3963         if (!allowedServiceValues.contains(NetworkRegistrationInfo.SERVICE_TYPE_DATA)
3964                 && getCarrierSatelliteDataSupportedModeFromConfig(subId)
3965                 == CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED) {
3966             return getSatelliteSupportedServicesFromConfig(subId, plmn)
3967                     .contains(NetworkRegistrationInfo.SERVICE_TYPE_DATA);
3968         }
3969         return false;
3970     }
3971 
3972     /**
3973      *  checks if mms service is allowed, to add part of list of services supported by satellite
3974      *  plmn, when no mms service is included at allowed services
3975      *
3976      * @param subId subscription id
3977      * @param plmn  The satellite plmn
3978      * @param allowedServiceValues allowed services info supported by entitlement
3979      * @return {@code true} is supports data service else {@code false}
3980      */
isMmsServiceUpdateRequired(int subId, String plmn, List<Integer> allowedServiceValues)3981     private boolean isMmsServiceUpdateRequired(int subId, String plmn,
3982             List<Integer> allowedServiceValues) {
3983         if (!allowedServiceValues.contains(NetworkRegistrationInfo.SERVICE_TYPE_MMS)) {
3984             return getSatelliteSupportedServicesFromConfig(subId, plmn)
3985                     .contains(NetworkRegistrationInfo.SERVICE_TYPE_MMS);
3986         }
3987         return false;
3988     }
3989 
3990     /**
3991      * Gives the list of satellite services associated with
3992      * {@link CarrierConfigManager#KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE}.
3993      * Note: If this config not found, fallback to
3994      * {@link CarrierConfigManager#KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY}.
3995      *
3996      * @param subId subsctiption id
3997      * @param plmn The satellite plmn
3998      * @return The list of services supported by the carrier associated with the
3999      */
getSatelliteSupportedServicesFromConfig(int subId, String plmn)4000     private List<Integer> getSatelliteSupportedServicesFromConfig(int subId, String plmn) {
4001         if (plmn != null && !plmn.isEmpty()) {
4002             synchronized (mSupportedSatelliteServicesLock) {
4003                 if (mSatelliteServicesSupportedByCarriersFromConfig.containsKey(subId)) {
4004                     Map<String, Set<Integer>> supportedServices =
4005                             mSatelliteServicesSupportedByCarriersFromConfig.get(subId);
4006                     if (supportedServices != null && supportedServices.containsKey(plmn)) {
4007                         return new ArrayList<>(supportedServices.get(plmn));
4008                     } else {
4009                         loge("getSupportedSatelliteServices: subId=" + subId
4010                                 + ", supportedServices "
4011                                 + "does not contain key plmn=" + plmn);
4012                     }
4013                 } else {
4014                     loge("getSupportedSatelliteServices: "
4015                             + "mSatelliteServicesSupportedByCarriersFromConfig does not contain"
4016                             + " key subId=" + subId);
4017                 }
4018             }
4019         }
4020 
4021         /* Returns default capabilities when carrier config does not contain service capabilities
4022          for the given plmn */
4023         PersistableBundle config = getPersistableBundle(subId);
4024         int [] defaultCapabilities = config.getIntArray(
4025                 KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY);
4026         if (defaultCapabilities == null) {
4027             logd("getSupportedSatelliteServices: defaultCapabilities is null");
4028             return new ArrayList<>();
4029         }
4030         List<Integer> capabilitiesList = Arrays.stream(
4031                 defaultCapabilities).boxed().collect(Collectors.toList());
4032         logd("getSupportedSatelliteServices: subId=" + subId
4033                 + ", supportedServices does not contain key plmn=" + plmn
4034                 + ", return default values " + capabilitiesList);
4035         return capabilitiesList;
4036     }
4037 
4038     /**
4039      * @param subId Subscription ID.
4040      * @param plmn The satellite plmn.
4041      * @return The list of services supported by the carrier associated with the {@code subId} for
4042      * the satellite network {@code plmn}. Returns empty list at invalid sub id.
4043      *
4044      */
4045     @NonNull
getSupportedSatelliteServicesForPlmn(int subId, String plmn)4046     public List<Integer> getSupportedSatelliteServicesForPlmn(int subId, String plmn) {
4047 
4048         if (!isValidSubscriptionId(subId)) {
4049             logd("getSupportedSatelliteServices: invalid sub id");
4050             return new ArrayList<>();
4051         }
4052         synchronized (mSupportedSatelliteServicesLock) {
4053             if (plmn != null && !plmn.isEmpty()) {
4054                 Map<String, List<Integer>> allowedServicesList =
4055                         mEntitlementServiceTypeMapPerCarrier.get(subId);
4056                 if (allowedServicesList != null && allowedServicesList.containsKey(plmn)) {
4057                     List<Integer> allowedServiceValues = new ArrayList<>(
4058                             allowedServicesList.get(plmn));
4059                     if (allowedServiceValues != null && !allowedServiceValues.isEmpty()) {
4060                         if (isDataServiceUpdateRequired(subId, plmn, allowedServiceValues)) {
4061                             logd("getSupportedSatelliteServices: data service added to satellite"
4062                                     + " plmn");
4063                             allowedServiceValues.add(NetworkRegistrationInfo.SERVICE_TYPE_DATA);
4064                         }
4065                         if (allowedServiceValues.contains(NetworkRegistrationInfo.SERVICE_TYPE_DATA)
4066                                 && isMmsServiceUpdateRequired(subId, plmn, allowedServiceValues)) {
4067                             allowedServiceValues.add(NetworkRegistrationInfo.SERVICE_TYPE_MMS);
4068                         }
4069                         return allowedServiceValues;
4070                     }
4071                 }
4072             }
4073 
4074             return getSatelliteSupportedServicesFromConfig(subId, plmn);
4075         }
4076 
4077     }
4078 
4079     /**
4080      * Check whether satellite modem has to attach to a satellite network before sending/receiving
4081      * datagrams.
4082      *
4083      * @return {@code true} if satellite attach is required, {@code false} otherwise.
4084      */
isSatelliteAttachRequired()4085     public boolean isSatelliteAttachRequired() {
4086         SatelliteCapabilities satelliteCapabilities = getSatelliteCapabilities();
4087         if (satelliteCapabilities == null) {
4088             ploge("isSatelliteAttachRequired: mSatelliteCapabilities is null");
4089             return false;
4090         }
4091         if (satelliteCapabilities.getSupportedRadioTechnologies().contains(
4092                 SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN)) {
4093             return true;
4094         }
4095         return false;
4096     }
4097 
4098     /**
4099      * @return {@code true} if satellite is supported via carrier by any subscription on the device,
4100      * {@code false} otherwise.
4101      */
isSatelliteSupportedViaCarrier()4102     public boolean isSatelliteSupportedViaCarrier() {
4103         for (Phone phone : PhoneFactory.getPhones()) {
4104             if (isSatelliteSupportedViaCarrier(phone.getSubId())) {
4105                 return true;
4106             }
4107         }
4108         return false;
4109     }
4110 
4111     /**
4112      * @return {@code true} if satellite emergency messaging is supported via carrier by any
4113      * subscription on the device, {@code false} otherwise.
4114      */
isSatelliteEmergencyMessagingSupportedViaCarrier()4115     public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
4116         for (Phone phone : PhoneFactory.getPhones()) {
4117             if (isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
4118                 return true;
4119             }
4120         }
4121         return false;
4122     }
4123 
isSatelliteEmergencyMessagingSupportedViaCarrier(int subId)4124     private boolean isSatelliteEmergencyMessagingSupportedViaCarrier(int subId) {
4125         if (!isSatelliteSupportedViaCarrier(subId)) {
4126             return false;
4127         }
4128         PersistableBundle config = getPersistableBundle(subId);
4129         return config.getBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL);
4130     }
4131 
4132     /**
4133      * @return {@code Pair<true, subscription ID>} if any subscription on the device is connected to
4134      * satellite, {@code Pair<false, null>} otherwise.
4135      */
isUsingNonTerrestrialNetworkViaCarrier()4136     Pair<Boolean, Integer> isUsingNonTerrestrialNetworkViaCarrier() {
4137         for (Phone phone : PhoneFactory.getPhones()) {
4138             ServiceState serviceState = phone.getServiceState();
4139             if (serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) {
4140                 return new Pair<>(true, phone.getSubId());
4141             }
4142         }
4143         return new Pair<>(false, null);
4144     }
4145 
4146     /**
4147      * @return {@code true} and the corresponding subId if the device is connected to
4148      * satellite via any carrier within the
4149      * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
4150      * duration, {@code false} and null otherwise.
4151      */
isSatelliteConnectedViaCarrierWithinHysteresisTime()4152     public Pair<Boolean, Integer> isSatelliteConnectedViaCarrierWithinHysteresisTime() {
4153         Pair<Boolean, Integer> ntnConnectedState = isUsingNonTerrestrialNetworkViaCarrier();
4154         if (ntnConnectedState.first) {
4155             return ntnConnectedState;
4156         }
4157         for (Phone phone : PhoneFactory.getPhones()) {
4158             if (isInSatelliteModeForCarrierRoaming(phone)) {
4159                 logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: "
4160                         + "subId:" + phone.getSubId()
4161                         + " is connected to satellite within hysteresis time");
4162                 return new Pair<>(true, phone.getSubId());
4163             }
4164         }
4165         return new Pair<>(false, null);
4166     }
4167 
4168     /**
4169      * Get whether device is connected to satellite via carrier.
4170      *
4171      * @param phone phone object
4172      * @return {@code true} if the device is connected to satellite using the phone within the
4173      * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
4174      * duration, {@code false} otherwise.
4175      */
isInSatelliteModeForCarrierRoaming(@ullable Phone phone)4176     public boolean isInSatelliteModeForCarrierRoaming(@Nullable Phone phone) {
4177         if (phone == null) {
4178             return false;
4179         }
4180 
4181         int subId = phone.getSubId();
4182         int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
4183         if (carrierRoamingNtnConnectType == CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
4184             return isInCarrierRoamingNbIotNtn(phone);
4185         }
4186 
4187         if (!isSatelliteSupportedViaCarrier(subId)) {
4188             return false;
4189         }
4190 
4191         ServiceState serviceState = phone.getServiceState();
4192         if (serviceState == null) {
4193             return false;
4194         }
4195 
4196         if (serviceState.isUsingNonTerrestrialNetwork()) {
4197             return true;
4198         }
4199 
4200         if (getWwanIsInService(serviceState)
4201                 || serviceState.getState() == ServiceState.STATE_POWER_OFF) {
4202             // Device is connected to terrestrial network which has coverage or radio is turned off
4203             resetCarrierRoamingSatelliteModeParams(subId);
4204             return false;
4205         }
4206 
4207         synchronized (mSatelliteConnectedLock) {
4208             Long lastDisconnectedTime = mLastSatelliteDisconnectedTimesMillis.get(subId);
4209             long satelliteConnectionHysteresisTime =
4210                     getSatelliteConnectionHysteresisTimeMillis(subId);
4211             if (lastDisconnectedTime != null
4212                     && (getElapsedRealtime() - lastDisconnectedTime)
4213                     <= satelliteConnectionHysteresisTime) {
4214                 logd("isInSatelliteModeForCarrierRoaming: " + "subId:" + subId
4215                         + " is connected to satellite within hysteresis time");
4216                 return true;
4217             } else {
4218                 resetCarrierRoamingSatelliteModeParams(subId);
4219                 return false;
4220             }
4221         }
4222     }
4223 
4224     /**
4225      * @return {@code true} if should exit satellite mode unless already sent a datagram in this
4226      * esos session.
4227      */
shouldTurnOffCarrierSatelliteForEmergencyCall()4228     public boolean shouldTurnOffCarrierSatelliteForEmergencyCall() {
4229         return !mDatagramController.isEmergencyCommunicationEstablished()
4230                 && getConfigForSubId(getSelectedSatelliteSubId()).getBoolean(
4231                 KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL);
4232     }
4233 
4234     /**
4235      * Return whether the satellite request is for an emergency or not.
4236      *
4237      * @return {@code true} if the satellite request is for an emergency and
4238      *                      {@code false} otherwise.
4239      */
getRequestIsEmergency()4240     public boolean getRequestIsEmergency() {
4241         return mIsEmergency;
4242     }
4243 
4244     /**
4245      * @return {@code true} if device is in carrier roaming nb iot ntn mode,
4246      * else {@return false}
4247      */
isInCarrierRoamingNbIotNtn()4248     public boolean isInCarrierRoamingNbIotNtn() {
4249         return isInCarrierRoamingNbIotNtn(getSatellitePhone());
4250     }
4251 
4252     /**
4253      * @return {@code true} if phone is in carrier roaming nb iot ntn mode,
4254      * else {@return false}
4255      */
isInCarrierRoamingNbIotNtn(@ullable Phone phone)4256     public boolean isInCarrierRoamingNbIotNtn(@Nullable Phone phone) {
4257         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
4258             plogd("isInCarrierRoamingNbIotNtn: carrier roaming nb iot ntn "
4259                     + "feature flag is disabled");
4260             return false;
4261         }
4262 
4263         if (!isSatelliteEnabled()) {
4264             plogd("iisInCarrierRoamingNbIotNtn: satellite is disabled");
4265             return false;
4266         }
4267 
4268         if (phone == null) {
4269             plogd("isInCarrierRoamingNbIotNtn: phone is null");
4270             return false;
4271         }
4272 
4273         int subId = phone.getSubId();
4274         if (!isSatelliteSupportedViaCarrier(subId)) {
4275             plogd("isInCarrierRoamingNbIotNtn[phoneId=" + phone.getPhoneId()
4276                     + "]: satellite is not supported via carrier");
4277             return false;
4278         }
4279 
4280         int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
4281         if (carrierRoamingNtnConnectType != CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
4282             plogd("isInCarrierRoamingNbIotNtn[phoneId=" + phone.getPhoneId() + "]: not manual "
4283                     + "connect. carrierRoamingNtnConnectType = " + carrierRoamingNtnConnectType);
4284             return false;
4285         }
4286 
4287         if (subId != getSelectedSatelliteSubId()) {
4288             plogd("isInCarrierRoamingNbIotNtn: subId=" + subId
4289                     + " does not match satellite subId=" + getSelectedSatelliteSubId());
4290             return false;
4291         }
4292 
4293         plogd("isInCarrierRoamingNbIotNtn: carrier roaming ntn eligible for phone"
4294                   + " associated with subId " + phone.getSubId());
4295         return true;
4296     }
4297 
4298     /**
4299      * Return capabilities of carrier roaming satellite network.
4300      *
4301      * @param phone phone object
4302      * @return The list of services supported by the carrier associated with the {@code subId}
4303      */
4304     @NonNull
getCapabilitiesForCarrierRoamingSatelliteMode(Phone phone)4305     public List<Integer> getCapabilitiesForCarrierRoamingSatelliteMode(Phone phone) {
4306         synchronized (mSatelliteConnectedLock) {
4307             int subId = phone.getSubId();
4308             if (mSatModeCapabilitiesForCarrierRoaming.containsKey(subId)) {
4309                 return mSatModeCapabilitiesForCarrierRoaming.get(subId);
4310             }
4311         }
4312 
4313         return new ArrayList<>();
4314     }
4315 
4316     /**
4317      * Request to get the {@link SatelliteSessionStats} of the satellite service.
4318      *
4319      * @param subId The subId of the subscription to the satellite session stats for.
4320      * @param result The result receiver that returns the {@link SatelliteSessionStats}
4321      *               if the request is successful or an error code if the request failed.
4322      */
requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result)4323     public void requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result) {
4324         mSessionMetricsStats.requestSatelliteSessionStats(subId, result);
4325     }
4326 
4327     /**
4328      * Get the carrier-enabled emergency call wait for connection timeout millis
4329      */
getCarrierEmergencyCallWaitForConnectionTimeoutMillis()4330     public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
4331         long maxTimeoutMillis = 0;
4332         for (Phone phone : PhoneFactory.getPhones()) {
4333             if (!isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
4334                 continue;
4335             }
4336 
4337             int timeoutMillis =
4338                     getCarrierEmergencyCallWaitForConnectionTimeoutMillis(phone.getSubId());
4339             // Prioritize getting the timeout duration from the phone that is in satellite mode
4340             // with carrier roaming
4341             if (isInSatelliteModeForCarrierRoaming(phone)) {
4342                 return timeoutMillis;
4343             }
4344             if (maxTimeoutMillis < timeoutMillis) {
4345                 maxTimeoutMillis = timeoutMillis;
4346             }
4347         }
4348         if (maxTimeoutMillis != 0) {
4349             return maxTimeoutMillis;
4350         }
4351         return DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
4352     }
4353 
getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId)4354     public int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
4355         PersistableBundle config = getPersistableBundle(subId);
4356         return config.getInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
4357     }
4358 
4359     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getElapsedRealtime()4360     protected long getElapsedRealtime() {
4361         return SystemClock.elapsedRealtime();
4362     }
4363 
4364     /**
4365      * Register the handler for SIM Refresh notifications.
4366      * @param handler Handler for notification message.
4367      * @param what User-defined message code.
4368      */
registerIccRefresh(Handler handler, int what)4369     public void registerIccRefresh(Handler handler, int what) {
4370         for (Phone phone : PhoneFactory.getPhones()) {
4371             CommandsInterface ci = phone.mCi;
4372             ci.registerForIccRefresh(handler, what, null);
4373         }
4374     }
4375 
4376     /**
4377      * Unregister the handler for SIM Refresh notifications.
4378      * @param handler Handler for notification message.
4379      */
unRegisterIccRefresh(Handler handler)4380     public void unRegisterIccRefresh(Handler handler) {
4381         for (Phone phone : PhoneFactory.getPhones()) {
4382             CommandsInterface ci = phone.mCi;
4383             ci.unregisterForIccRefresh(handler);
4384         }
4385     }
4386 
4387     /**
4388      * To use the satellite service, update the EntitlementStatus, PlmnAllowedList, barred plmn list
4389      * data plan, service type, data service policy and voice service policy after receiving the
4390      * satellite configuration from the entitlement server. If satellite entitlement is enabled,
4391      * enable satellite for the carrier. Otherwise, disable satellite.
4392      *
4393      * @param subId                     Subscription ID
4394      * @param entitlementEnabled        {@code true} enables Satellite entitlement service.
4395      * @param allowedPlmnList           Plmn [MCC+MNC] list of codes to determine if satellite
4396      *                                  communication is allowed. Ex : "123123,12310".
4397      * @param barredPlmnList            Plmn [MCC+MNC] list of codes to determine if satellite
4398      *                                  communication is not allowed.  Ex : "123123,12310".
4399      * @param plmnDataPlanMap           data plan per plmn of type {@link SatelliteDataPlan}.
4400      *                                  Ex : {"302820":0, "31026":1}.
4401      * @param plmnServiceTypeMap        list of supported services per plmn of type
4402      *                                  {@link NetworkRegistrationInfo.ServiceType}).
4403      *                                  Ex : {"302820":[1,3],"31026":[2,3]}.
4404      * @param plmnDataServicePolicyMap  data support mode per plmn map of types
4405      *                                  {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}.
4406      *                                  Ex : {"302820":2, "31026":1}.
4407      * @param plmnVoiceServicePolicyMap voice support mode per plmn map of types
4408      *                                  {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}.
4409      *                                  Ex : {"302820":2, "31026":1}.
4410      * @param callback                  callback for accept.
4411      */
onSatelliteEntitlementStatusUpdated(int subId, boolean entitlementEnabled, @Nullable List<String> allowedPlmnList, @Nullable List<String> barredPlmnList, @Nullable Map<String,Integer> plmnDataPlanMap, @Nullable Map<String,List<Integer>> plmnServiceTypeMap, @Nullable Map<String,Integer> plmnDataServicePolicyMap, @Nullable Map<String,Integer> plmnVoiceServicePolicyMap, @Nullable IIntegerConsumer callback)4412     public void onSatelliteEntitlementStatusUpdated(int subId, boolean entitlementEnabled,
4413             @Nullable List<String> allowedPlmnList, @Nullable List<String> barredPlmnList,
4414             @Nullable Map<String,Integer> plmnDataPlanMap,
4415             @Nullable Map<String,List<Integer>> plmnServiceTypeMap,
4416             @Nullable Map<String,Integer> plmnDataServicePolicyMap,
4417             @Nullable Map<String,Integer> plmnVoiceServicePolicyMap,
4418             @Nullable IIntegerConsumer callback) {
4419         if (callback == null) {
4420             callback = new IIntegerConsumer.Stub() {
4421                 @Override
4422                 public void accept(int result) {
4423                     logd("updateSatelliteEntitlementStatus:" + result);
4424                 }
4425             };
4426         }
4427         if (allowedPlmnList == null) {
4428             allowedPlmnList = new ArrayList<>();
4429         }
4430         if (barredPlmnList == null) {
4431             barredPlmnList = new ArrayList<>();
4432         }
4433         if (plmnDataPlanMap == null) {
4434             plmnDataPlanMap = new HashMap<>();
4435         }
4436         if (plmnServiceTypeMap == null) {
4437             plmnServiceTypeMap = new HashMap<>();
4438         }
4439         if (plmnDataServicePolicyMap == null) {
4440             plmnDataServicePolicyMap = new HashMap<>();
4441         }
4442         if (plmnVoiceServicePolicyMap == null) {
4443             plmnVoiceServicePolicyMap = new HashMap<>();
4444         }
4445         logd("onSatelliteEntitlementStatusUpdated subId=" + subId + ", entitlementEnabled="
4446                 + entitlementEnabled + ", allowedPlmnList=["
4447                 + String.join(",", allowedPlmnList) + "]" + ", barredPlmnList=["
4448                 + String.join(",", barredPlmnList) + "]"
4449                 + ", plmnDataPlanMap =" + plmnDataPlanMap.toString()
4450                 + ", plmnServiceTypeMap =" + plmnServiceTypeMap.toString()
4451                 + ", plmnDataServicePolicyMap=" + plmnDataServicePolicyMap.toString()
4452                 + ", plmnVoiceServicePolicyMap=" + plmnVoiceServicePolicyMap.toString());
4453 
4454         synchronized (mSupportedSatelliteServicesLock) {
4455             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false) != entitlementEnabled) {
4456                 logd("update the carrier satellite enabled to " + entitlementEnabled);
4457                 mSatelliteEntitlementStatusPerCarrier.put(subId, entitlementEnabled);
4458                 mCarrierRoamingSatelliteControllerStats.reportIsDeviceEntitled(subId,
4459                         entitlementEnabled);
4460                 if (hasMessages(EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT)) {
4461                     removeMessages(EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT);
4462                     sendMessageDelayed(obtainMessage(
4463                                     EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT),
4464                             WAIT_FOR_REPORT_ENTITLED_MERTICS_TIMEOUT_MILLIS);
4465                 }
4466                 try {
4467                     mSubscriptionManagerService.setSubscriptionProperty(subId,
4468                             SATELLITE_ENTITLEMENT_STATUS, entitlementEnabled ? "1" : "0");
4469                 } catch (IllegalArgumentException | SecurityException e) {
4470                     loge("onSatelliteEntitlementStatusUpdated: setSubscriptionProperty, e=" + e);
4471                 }
4472             }
4473 
4474             if (isValidPlmnList(allowedPlmnList) && isValidPlmnList(barredPlmnList)) {
4475                 mMergedPlmnListPerCarrier.remove(subId);
4476                 mEntitlementPlmnListPerCarrier.put(subId, allowedPlmnList);
4477                 mEntitlementBarredPlmnListPerCarrier.put(subId, barredPlmnList);
4478                 mEntitlementDataPlanMapPerCarrier.put(subId, plmnDataPlanMap);
4479                 mEntitlementDataServicePolicyMapPerCarrier.put(subId, plmnDataServicePolicyMap);
4480                 mEntitlementVoiceServicePolicyMapPerCarrier.put(subId, plmnVoiceServicePolicyMap);
4481                 updateAndNotifyChangesInCarrierRoamingNtnAvailableServices(subId,
4482                         plmnServiceTypeMap);
4483                 updatePlmnListPerCarrier(subId);
4484 
4485                 configureSatellitePlmnForCarrier(subId);
4486                 evaluateEnablingSatelliteForCarrier(subId,
4487                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, null);
4488                 mSubscriptionManagerService.setSatelliteEntitlementInfo(subId, allowedPlmnList,
4489                         barredPlmnList, plmnDataPlanMap, plmnServiceTypeMap,
4490                         plmnDataServicePolicyMap, plmnVoiceServicePolicyMap);
4491 
4492             } else {
4493                 loge("onSatelliteEntitlementStatusUpdated: either invalid allowedPlmnList "
4494                         + "or invalid barredPlmnList");
4495             }
4496 
4497             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false)) {
4498                 removeAttachRestrictionForCarrier(subId,
4499                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
4500             } else {
4501                 addAttachRestrictionForCarrier(subId,
4502                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
4503             }
4504         }
4505     }
4506 
4507     /**
4508      * A list of PLMNs is considered valid if either the list is empty or all PLMNs in the list
4509      * are valid.
4510      */
isValidPlmnList(@onNull List<String> plmnList)4511     private boolean isValidPlmnList(@NonNull List<String> plmnList) {
4512         for (String plmn : plmnList) {
4513             if (!TelephonyUtils.isValidPlmn(plmn)) {
4514                 ploge("Invalid PLMN = " + plmn);
4515                 return false;
4516             }
4517         }
4518         return true;
4519     }
4520 
4521     /**
4522      * If we have not successfully queried the satellite modem for its satellite service support,
4523      * we will retry the query one more time. Otherwise, we will return the cached result.
4524      */
isSatelliteSupportedViaOemInternal()4525     private Boolean isSatelliteSupportedViaOemInternal() {
4526         Boolean isSatelliteSupported = getIsSatelliteSupported();
4527         if (isSatelliteSupported != null) {
4528             /* We have already successfully queried the satellite modem. */
4529             return isSatelliteSupported;
4530         }
4531 
4532         /**
4533          * We have not successfully checked whether the modem supports satellite service.
4534          * Thus, we need to retry it now.
4535          */
4536         requestIsSatelliteSupported(
4537                 new ResultReceiver(this) {
4538                     @Override
4539                     protected void onReceiveResult(int resultCode, Bundle resultData) {
4540                         decrementResultReceiverCount(
4541                                 "SC:isSatelliteSupportedViaOemInternal");
4542                         plogd("isSatelliteSupportedViaOemInternal.requestIsSatelliteSupported:"
4543                                 + " resultCode=" + resultCode);
4544                     }
4545                 });
4546         incrementResultReceiverCount("SC:isSatelliteSupportedViaOemInternal");
4547         return null;
4548     }
4549 
handleEventProvisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteResult int result)4550     private void handleEventProvisionSatelliteServiceDone(
4551             @NonNull ProvisionSatelliteServiceArgument arg,
4552             @SatelliteManager.SatelliteResult int result) {
4553         plogd("handleEventProvisionSatelliteServiceDone: result="
4554                 + result + ", subId=" + arg.subId);
4555 
4556         Consumer<Integer> callback = mSatelliteProvisionCallbacks.remove(arg.subId);
4557         if (callback == null) {
4558             ploge("handleEventProvisionSatelliteServiceDone: callback is null for subId="
4559                     + arg.subId);
4560             mProvisionMetricsStats
4561                     .setResultCode(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE)
4562                     .setIsProvisionRequest(true)
4563                     .setCarrierId(getSatelliteCarrierId())
4564                     .setIsNtnOnlyCarrier(isNtnOnlyCarrier())
4565                     .reportProvisionMetrics();
4566             mControllerMetricsStats.reportProvisionCount(
4567                     SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
4568             return;
4569         }
4570         if (result == SATELLITE_RESULT_SUCCESS
4571                 || result == SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
4572             persistOemEnabledSatelliteProvisionStatus(true);
4573             callback.accept(SATELLITE_RESULT_SUCCESS);
4574             updateCachedDeviceProvisionStatus();
4575         } else {
4576             callback.accept(result);
4577         }
4578         mProvisionMetricsStats.setResultCode(result)
4579                 .setIsProvisionRequest(true)
4580                 .setCarrierId(getSatelliteCarrierId())
4581                 .setIsNtnOnlyCarrier(isNtnOnlyCarrier())
4582                 .reportProvisionMetrics();
4583         mControllerMetricsStats.reportProvisionCount(result);
4584     }
4585 
handleEventDeprovisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteResult int result)4586     private void handleEventDeprovisionSatelliteServiceDone(
4587             @NonNull ProvisionSatelliteServiceArgument arg,
4588             @SatelliteManager.SatelliteResult int result) {
4589         if (arg == null) {
4590             ploge("handleEventDeprovisionSatelliteServiceDone: arg is null");
4591             return;
4592         }
4593         plogd("handleEventDeprovisionSatelliteServiceDone: result="
4594                 + result + ", subId=" + arg.subId);
4595 
4596         if (result == SATELLITE_RESULT_SUCCESS
4597                 || result == SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
4598             persistOemEnabledSatelliteProvisionStatus(false);
4599             if (arg.callback != null) {
4600                 arg.callback.accept(SATELLITE_RESULT_SUCCESS);
4601             }
4602             updateCachedDeviceProvisionStatus();
4603         } else if (arg.callback != null) {
4604             arg.callback.accept(result);
4605         }
4606         mProvisionMetricsStats.setResultCode(result)
4607                 .setIsProvisionRequest(false)
4608                 .setCarrierId(getSatelliteCarrierId())
4609                 .setIsNtnOnlyCarrier(isNtnOnlyCarrier())
4610                 .reportProvisionMetrics();
4611         mControllerMetricsStats.reportDeprovisionCount(result);
4612     }
4613 
handleStartSatelliteTransmissionUpdatesDone(@onNull AsyncResult ar)4614     private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) {
4615         SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj;
4616         SatelliteTransmissionUpdateArgument arg =
4617                 (SatelliteTransmissionUpdateArgument) request.argument;
4618         int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
4619                 "handleStartSatelliteTransmissionUpdatesDone");
4620         arg.errorCallback.accept(errorCode);
4621 
4622         if (errorCode != SATELLITE_RESULT_SUCCESS) {
4623             mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
4624             // We need to remove the callback from our listener list since the caller might not call
4625             // stopSatelliteTransmissionUpdates to unregister the callback in case of failure.
4626             mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId,
4627                     arg.errorCallback, arg.callback);
4628         } else {
4629             mPointingAppController.setStartedSatelliteTransmissionUpdates(true);
4630         }
4631     }
4632 
4633     /**
4634      * Posts the specified command to be executed on the main thread and returns immediately.
4635      *
4636      * @param command command to be executed on the main thread
4637      * @param argument additional parameters required to perform of the operation
4638      * @param phone phone object used to perform the operation.
4639      */
sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone)4640     private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) {
4641         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
4642                 argument, phone);
4643         Message msg = this.obtainMessage(command, request);
4644         msg.sendToTarget();
4645     }
4646 
4647     /**
4648      * Check if satellite is provisioned for the device.
4649      * @return {@code true} if device is provisioned for satellite else return {@code false}.
4650      */
4651     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
4652     @Nullable
isDeviceProvisioned()4653     protected Boolean isDeviceProvisioned() {
4654         synchronized (mDeviceProvisionLock) {
4655             if (mOverriddenIsSatelliteViaOemProvisioned != null) {
4656                 return mOverriddenIsSatelliteViaOemProvisioned;
4657             }
4658 
4659             if (mIsDeviceProvisioned == null) {
4660                 mIsDeviceProvisioned = getPersistedDeviceProvisionStatus();
4661             }
4662             return mIsDeviceProvisioned;
4663         }
4664     }
4665 
handleSatelliteEnabled(SatelliteControllerHandlerRequest request)4666     private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) {
4667         RequestSatelliteEnabledArgument argument =
4668                 (RequestSatelliteEnabledArgument) request.argument;
4669         handlePersistentLoggingOnSessionStart(argument);
4670         selectBindingSatelliteSubscription(false);
4671         SatelliteModemEnableRequestAttributes enableRequestAttributes =
4672                     createModemEnableRequest(argument);
4673         if (enableRequestAttributes == null) {
4674             plogw("handleSatelliteEnabled: enableRequestAttributes is null");
4675             sendErrorAndReportSessionMetrics(
4676                     SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, argument.callback);
4677             synchronized (mSatelliteEnabledRequestLock) {
4678                 if (argument.enableSatellite) {
4679                     mSatelliteEnabledRequest = null;
4680                 } else {
4681                     mSatelliteDisabledRequest = null;
4682                 }
4683             }
4684             return;
4685         }
4686 
4687         if (mSatelliteSessionController != null) {
4688             mSatelliteSessionController.onSatelliteEnablementStarted(argument.enableSatellite);
4689         } else {
4690             ploge("handleSatelliteEnabled: mSatelliteSessionController is not initialized yet");
4691         }
4692 
4693         /* Framework will send back the disable result to the requesting client only after receiving
4694          * both confirmation for the disable request from modem, and OFF state from modem if the
4695          * modem is not in OFF state.
4696          */
4697         if (!argument.enableSatellite && mSatelliteModemInterface.isSatelliteServiceSupported()) {
4698             synchronized (mSatelliteEnabledRequestLock) {
4699                 mWaitingForDisableSatelliteModemResponse = true;
4700                 if (!isSatelliteDisabled()) mWaitingForSatelliteModemOff = true;
4701             }
4702         }
4703 
4704         Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request);
4705         mSatelliteModemInterface.requestSatelliteEnabled(
4706                 enableRequestAttributes, onCompleted);
4707         startWaitForSatelliteEnablingResponseTimer(argument);
4708         // Logs satellite session timestamps for session metrics
4709         if (argument.enableSatellite) {
4710             mSessionStartTimeStamp = getElapsedRealtime();
4711         }
4712         mSessionProcessingTimeStamp = getElapsedRealtime();
4713     }
4714 
4715     /** Get the request attributes that modem needs to enable/disable satellite */
createModemEnableRequest( @onNull RequestSatelliteEnabledArgument arg)4716     @Nullable private SatelliteModemEnableRequestAttributes createModemEnableRequest(
4717             @NonNull RequestSatelliteEnabledArgument arg) {
4718         int subId = getSelectedSatelliteSubId();
4719         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
4720         if (subInfo == null) {
4721             loge("createModemEnableRequest: no SubscriptionInfo found for subId=" + subId);
4722             return null;
4723         }
4724         String iccid = subInfo.getIccId();
4725         String apn = getNiddApnName(subId);
4726         return new SatelliteModemEnableRequestAttributes(
4727                 arg.enableSatellite, arg.enableDemoMode, arg.isEmergency,
4728                 new SatelliteSubscriptionInfo(iccid, apn));
4729     }
4730 
getNiddApnName(int subId)4731     @NonNull private String getNiddApnName(int subId) {
4732         if (SatelliteServiceUtils.isNtnOnlySubscriptionId(subId)) {
4733             String apn = mContext.getResources().getString(R.string.config_satellite_nidd_apn_name);
4734             if (!TextUtils.isEmpty(apn)) {
4735                 return apn;
4736             }
4737         }
4738         return getConfigForSubId(subId).getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
4739     }
4740 
handleRequestSatelliteAttachRestrictionForCarrierCmd( SatelliteControllerHandlerRequest request)4741     private void handleRequestSatelliteAttachRestrictionForCarrierCmd(
4742             SatelliteControllerHandlerRequest request) {
4743         RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
4744                 (RequestHandleSatelliteAttachRestrictionForCarrierArgument) request.argument;
4745 
4746         if (argument.reason == SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER) {
4747             if (!persistSatelliteAttachEnabledForCarrierSetting(argument.subId)) {
4748                 argument.callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
4749                 return;
4750             }
4751         }
4752 
4753         evaluateEnablingSatelliteForCarrier(argument.subId, argument.reason, argument.callback);
4754     }
4755 
updateSatelliteSupportedState(boolean supported)4756     private void updateSatelliteSupportedState(boolean supported) {
4757         synchronized (mIsSatelliteSupportedLock) {
4758             mIsSatelliteSupported = supported;
4759         }
4760         mSatelliteSessionController = SatelliteSessionController.make(
4761                 mContext, getLooper(), mFeatureFlags, supported);
4762         plogd("updateSatelliteSupportedState: create a new SatelliteSessionController because "
4763                 + "satellite supported state has changed to " + supported);
4764 
4765         if (supported) {
4766             registerForPendingDatagramCount();
4767             registerForSatelliteModemStateChanged();
4768             registerForNtnSignalStrengthChanged();
4769             registerForCapabilitiesChanged();
4770             registerForSatelliteRegistrationFailure();
4771             registerForTerrestrialNetworkAvailableChanged();
4772 
4773             requestIsSatelliteProvisioned(
4774                     new ResultReceiver(this) {
4775                         @Override
4776                         protected void onReceiveResult(int resultCode, Bundle resultData) {
4777                             plogd("updateSatelliteSupportedState.requestIsSatelliteProvisioned: "
4778                                     + "resultCode=" + resultCode + ", resultData=" + resultData);
4779                             decrementResultReceiverCount("SC:requestIsSatelliteProvisioned");
4780                             requestSatelliteEnabled(false, false, false,
4781                                     new IIntegerConsumer.Stub() {
4782                                         @Override
4783                                         public void accept(int result) {
4784                                             plogd("updateSatelliteSupportedState."
4785                                                     + "requestSatelliteEnabled: result=" + result);
4786                                         }
4787                                     });
4788                         }
4789                     });
4790             incrementResultReceiverCount("SC:requestIsSatelliteProvisioned");
4791 
4792             requestSatelliteCapabilities(
4793                     new ResultReceiver(this) {
4794                         @Override
4795                         protected void onReceiveResult(int resultCode, Bundle resultData) {
4796                             plogd("updateSatelliteSupportedState.requestSatelliteCapabilities: "
4797                                     + "resultCode=" + resultCode + ", resultData=" + resultData);
4798                             decrementResultReceiverCount("SC:requestSatelliteCapabilities");
4799                         }
4800                     });
4801             incrementResultReceiverCount("SC:requestSatelliteCapabilities");
4802         }
4803         registerForSatelliteSupportedStateChanged();
4804         selectBindingSatelliteSubscription(false);
4805         notifySatelliteSupportedStateChanged(supported);
4806     }
4807 
updateSatelliteEnabledState(boolean enabled, String caller)4808     private void updateSatelliteEnabledState(boolean enabled, String caller) {
4809         synchronized (mIsSatelliteEnabledLock) {
4810             mIsSatelliteEnabled = enabled;
4811         }
4812         if (mSatelliteSessionController != null) {
4813             mSatelliteSessionController.onSatelliteEnabledStateChanged(enabled);
4814             mSatelliteSessionController.setDemoMode(mIsDemoModeEnabled);
4815         } else {
4816             ploge(caller + ": mSatelliteSessionController is not initialized yet");
4817         }
4818         if (!enabled) {
4819             mIsModemEnabledReportingNtnSignalStrength.set(false);
4820         }
4821         if (mFeatureFlags.satelliteStateChangeListener()) {
4822             notifyEnabledStateChanged(enabled);
4823         }
4824     }
4825 
registerForPendingDatagramCount()4826     private void registerForPendingDatagramCount() {
4827         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4828             if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) {
4829                 mSatelliteModemInterface.registerForPendingDatagrams(
4830                         this, EVENT_PENDING_DATAGRAMS, null);
4831                 mRegisteredForPendingDatagramCountWithSatelliteService.set(true);
4832             }
4833         }
4834     }
4835 
registerForSatelliteModemStateChanged()4836     private void registerForSatelliteModemStateChanged() {
4837         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4838             if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) {
4839                 mSatelliteModemInterface.registerForSatelliteModemStateChanged(
4840                         this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
4841                 mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true);
4842             }
4843         }
4844     }
4845 
registerForNtnSignalStrengthChanged()4846     private void registerForNtnSignalStrengthChanged() {
4847         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4848             if (!mRegisteredForNtnSignalStrengthChanged.get()) {
4849                 mSatelliteModemInterface.registerForNtnSignalStrengthChanged(
4850                         this, EVENT_NTN_SIGNAL_STRENGTH_CHANGED, null);
4851                 mRegisteredForNtnSignalStrengthChanged.set(true);
4852             }
4853         }
4854     }
4855 
registerForCapabilitiesChanged()4856     private void registerForCapabilitiesChanged() {
4857         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4858             if (!mRegisteredForSatelliteCapabilitiesChanged.get()) {
4859                 mSatelliteModemInterface.registerForSatelliteCapabilitiesChanged(
4860                         this, EVENT_SATELLITE_CAPABILITIES_CHANGED, null);
4861                 mRegisteredForSatelliteCapabilitiesChanged.set(true);
4862             }
4863         }
4864     }
4865 
registerForSatelliteSupportedStateChanged()4866     private void registerForSatelliteSupportedStateChanged() {
4867         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4868             if (!mRegisteredForSatelliteSupportedStateChanged.get()) {
4869                 mSatelliteModemInterface.registerForSatelliteSupportedStateChanged(
4870                         this, EVENT_SATELLITE_SUPPORTED_STATE_CHANGED, null);
4871                 mRegisteredForSatelliteSupportedStateChanged.set(true);
4872             }
4873         }
4874     }
4875 
registerForSatelliteRegistrationFailure()4876     private void registerForSatelliteRegistrationFailure() {
4877         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
4878             if (!mRegisteredForSatelliteRegistrationFailure.get()) {
4879                 mSatelliteModemInterface.registerForSatelliteRegistrationFailure(this,
4880                         EVENT_SATELLITE_REGISTRATION_FAILURE, null);
4881                 mRegisteredForSatelliteRegistrationFailure.set(true);
4882             }
4883         }
4884     }
4885 
registerForTerrestrialNetworkAvailableChanged()4886     private void registerForTerrestrialNetworkAvailableChanged() {
4887         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
4888             if (!mRegisteredForTerrestrialNetworkAvailableChanged.get()) {
4889                 mSatelliteModemInterface.registerForTerrestrialNetworkAvailableChanged(this,
4890                         EVENT_TERRESTRIAL_NETWORK_AVAILABLE_CHANGED, null);
4891                 mRegisteredForTerrestrialNetworkAvailableChanged.set(true);
4892             }
4893         }
4894     }
4895 
notifyDeviceProvisionStateChanged(boolean provisioned)4896     private void notifyDeviceProvisionStateChanged(boolean provisioned) {
4897         List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>();
4898         mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
4899             try {
4900                 listener.onSatelliteProvisionStateChanged(provisioned);
4901             } catch (RemoteException e) {
4902                 plogd("notifyDeviceProvisionStateChanged RemoteException: " + e);
4903                 deadCallersList.add(listener);
4904             }
4905         });
4906         deadCallersList.forEach(listener -> {
4907             mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
4908         });
4909     }
4910 
updateSatelliteSubscriptionProvisionState(List<SatelliteSubscriberInfo> newList, boolean provisioned)4911     private boolean updateSatelliteSubscriptionProvisionState(List<SatelliteSubscriberInfo> newList,
4912             boolean provisioned) {
4913         logd("updateSatelliteSubscriptionProvisionState: List=" + newList + " , provisioned="
4914                 + provisioned);
4915         boolean provisionChanged = false;
4916         synchronized (mSatelliteTokenProvisionedLock) {
4917             for (SatelliteSubscriberInfo subscriberInfo : newList) {
4918 
4919                 int subId = subscriberInfo.getSubscriptionId();
4920                 Boolean currentProvisioned =
4921                         mProvisionedSubscriberId.get(subscriberInfo.getSubscriberId());
4922                 if (currentProvisioned == null) {
4923                     currentProvisioned = false;
4924                 }
4925 
4926                 Boolean isProvisionedInPersistentDb = false;
4927                 try {
4928                     isProvisionedInPersistentDb = mSubscriptionManagerService
4929                          .isSatelliteProvisionedForNonIpDatagram(subId);
4930                     if (isProvisionedInPersistentDb == null) {
4931                         isProvisionedInPersistentDb = false;
4932                     }
4933                 } catch (IllegalArgumentException | SecurityException ex) {
4934                     ploge("isSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex="
4935                             + ex);
4936                 }
4937                 if (currentProvisioned == provisioned
4938                         && isProvisionedInPersistentDb == provisioned) {
4939                     continue;
4940                 }
4941                 provisionChanged = true;
4942                 mProvisionedSubscriberId.put(subscriberInfo.getSubscriberId(), provisioned);
4943                 try {
4944                     mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId,
4945                             provisioned);
4946                     plogd("updateSatelliteSubscriptionProvisionState: set Provision state to db "
4947                             + "subId=" + subId);
4948                 } catch (IllegalArgumentException | SecurityException ex) {
4949                     ploge("setIsSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex="
4950                             + ex);
4951                 }
4952             }
4953         }
4954         return provisionChanged;
4955     }
4956 
handleEventSatelliteSubscriptionProvisionStateChanged()4957     private void handleEventSatelliteSubscriptionProvisionStateChanged() {
4958         List<SatelliteSubscriberProvisionStatus> informList =
4959                 getPrioritizedSatelliteSubscriberProvisionStatusList();
4960         plogd("handleEventSatelliteSubscriptionProvisionStateChanged: " + informList);
4961         notifySatelliteSubscriptionProvisionStateChanged(informList);
4962         updateCachedDeviceProvisionStatus();
4963         // Report updated provisioned status to metrics.
4964         synchronized (mSatelliteTokenProvisionedLock) {
4965             boolean isProvisioned = !mProvisionedSubscriberId.isEmpty()
4966                     && mProvisionedSubscriberId.containsValue(Boolean.TRUE);
4967             mControllerMetricsStats.setIsProvisioned(isProvisioned);
4968         }
4969         selectBindingSatelliteSubscription(false);
4970         evaluateCarrierRoamingNtnEligibilityChange();
4971     }
4972 
updateCachedDeviceProvisionStatus()4973     private void updateCachedDeviceProvisionStatus() {
4974         boolean isProvisioned = getPersistedDeviceProvisionStatus();
4975         plogd("updateCachedDeviceProvisionStatus: isProvisioned=" + isProvisioned);
4976         synchronized (mDeviceProvisionLock) {
4977             if (mIsDeviceProvisioned == null || mIsDeviceProvisioned != isProvisioned) {
4978                 mIsDeviceProvisioned = isProvisioned;
4979                 notifyDeviceProvisionStateChanged(isProvisioned);
4980             }
4981         }
4982     }
4983 
notifySatelliteSubscriptionProvisionStateChanged( @onNull List<SatelliteSubscriberProvisionStatus> list)4984     private void notifySatelliteSubscriptionProvisionStateChanged(
4985             @NonNull List<SatelliteSubscriberProvisionStatus> list) {
4986         List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>();
4987         mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
4988             try {
4989                 listener.onSatelliteSubscriptionProvisionStateChanged(list);
4990             } catch (RemoteException e) {
4991                 plogd("notifySatelliteSubscriptionProvisionStateChanged: " + e);
4992                 deadCallersList.add(listener);
4993             }
4994         });
4995         deadCallersList.forEach(listener -> {
4996             mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
4997         });
4998     }
4999 
handleEventSatelliteModemStateChanged( @atelliteManager.SatelliteModemState int state)5000     private void handleEventSatelliteModemStateChanged(
5001             @SatelliteManager.SatelliteModemState int state) {
5002         plogd("handleEventSatelliteModemStateChanged: state=" + state);
5003 
5004         synchronized (mSatelliteModemStateLock) {
5005             mSatelliteModemState = state;
5006         }
5007 
5008         if (state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE
5009                 || state == SatelliteManager.SATELLITE_MODEM_STATE_OFF) {
5010             if (!isWaitingForDisableSatelliteModemResponse()) {
5011                 moveSatelliteToOffStateAndCleanUpResources(SATELLITE_RESULT_SUCCESS);
5012             } else {
5013                 notifyModemStateChangedToSessionController(
5014                         SatelliteManager.SATELLITE_MODEM_STATE_OFF);
5015             }
5016 
5017             synchronized (mSatelliteEnabledRequestLock) {
5018                 mWaitingForSatelliteModemOff = false;
5019             }
5020         } else {
5021             if (isSatelliteEnabledOrBeingEnabled() || isSatelliteBeingDisabled()) {
5022                 notifyModemStateChangedToSessionController(state);
5023             } else {
5024                 // Telephony framework and modem are out of sync. We need to disable
5025                 synchronized (mSatelliteEnabledRequestLock) {
5026                     plogw("Satellite modem is in a bad state. Disabling satellite modem now ...");
5027                     Consumer<Integer> result = integer -> plogd(
5028                             "handleEventSatelliteModemStateChanged: disabling satellite result="
5029                                     + integer);
5030                     mSatelliteDisabledRequest = new RequestSatelliteEnabledArgument(
5031                             false /* enableSatellite */, false /* enableDemoMode */,
5032                             false /* isEmergency */, result);
5033                     sendRequestAsync(CMD_SET_SATELLITE_ENABLED, mSatelliteDisabledRequest, null);
5034                 }
5035             }
5036         }
5037     }
5038 
notifyModemStateChangedToSessionController( @atelliteManager.SatelliteModemState int state)5039     private void notifyModemStateChangedToSessionController(
5040             @SatelliteManager.SatelliteModemState int state) {
5041         if (mSatelliteSessionController != null) {
5042             mSatelliteSessionController.onSatelliteModemStateChanged(state);
5043         } else {
5044             ploge("notifyModemStateChangedToSessionController: mSatelliteSessionController is "
5045                     + "null");
5046         }
5047     }
5048 
handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength)5049     private void handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
5050         logd("handleEventNtnSignalStrengthChanged: ntnSignalStrength=" + ntnSignalStrength);
5051         synchronized (mNtnSignalsStrengthLock) {
5052             mNtnSignalStrength = ntnSignalStrength;
5053         }
5054         mSessionMetricsStats.updateMaxNtnSignalStrengthLevel(ntnSignalStrength.getLevel());
5055 
5056         List<INtnSignalStrengthCallback> deadCallersList = new ArrayList<>();
5057         mNtnSignalStrengthChangedListeners.values().forEach(listener -> {
5058             try {
5059                 listener.onNtnSignalStrengthChanged(ntnSignalStrength);
5060             } catch (RemoteException e) {
5061                 plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e);
5062                 deadCallersList.add(listener);
5063             }
5064         });
5065         deadCallersList.forEach(listener -> {
5066             mNtnSignalStrengthChangedListeners.remove(listener.asBinder());
5067         });
5068     }
5069 
handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities)5070     private void handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) {
5071         plogd("handleEventSatelliteCapabilitiesChanged()");
5072 
5073         synchronized (mSatelliteCapabilitiesLock) {
5074             mSatelliteCapabilities = capabilities;
5075         }
5076         overrideSatelliteCapabilitiesIfApplicable();
5077 
5078         SatelliteCapabilities satelliteCapabilities = getSatelliteCapabilities();
5079         List<ISatelliteCapabilitiesCallback> deadCallersList = new ArrayList<>();
5080         mSatelliteCapabilitiesChangedListeners.values().forEach(listener -> {
5081             try {
5082                 listener.onSatelliteCapabilitiesChanged(satelliteCapabilities);
5083             } catch (RemoteException e) {
5084                 plogd("handleEventSatelliteCapabilitiesChanged RemoteException: " + e);
5085                 deadCallersList.add(listener);
5086             }
5087         });
5088         deadCallersList.forEach(listener -> {
5089             mSatelliteCapabilitiesChangedListeners.remove(listener.asBinder());
5090         });
5091     }
5092 
handleEventSatelliteSupportedStateChanged(boolean supported)5093     private void handleEventSatelliteSupportedStateChanged(boolean supported) {
5094         plogd("handleSatelliteSupportedStateChangedEvent: supported=" + supported);
5095 
5096         Boolean isSatelliteSupported = getIsSatelliteSupported();
5097         if (isSatelliteSupported != null && isSatelliteSupported == supported) {
5098             if (DBG) {
5099                 plogd("current satellite support state and new supported state are matched,"
5100                         + " ignore update.");
5101             }
5102             return;
5103         }
5104 
5105         updateSatelliteSupportedState(supported);
5106 
5107         Boolean isSatelliteEnabled = getIsSatelliteEnabled();
5108          /* In case satellite has been reported as not support from modem, but satellite is
5109                enabled, request disable satellite. */
5110         if (!supported && isSatelliteEnabled != null && isSatelliteEnabled) {
5111             plogd("Invoke requestSatelliteEnabled(), supported=false, "
5112                     + "mIsSatelliteEnabled=true");
5113             requestSatelliteEnabled(false /* enableSatellite */, false /* enableDemoMode */,
5114                     false /* isEmergency */,
5115                     new IIntegerConsumer.Stub() {
5116                         @Override
5117                         public void accept(int result) {
5118                             plogd("handleSatelliteSupportedStateChangedEvent: request "
5119                                     + "satellite disable, result=" + result);
5120                         }
5121                     });
5122 
5123         }
5124 
5125         synchronized (mIsSatelliteSupportedLock) {
5126             mIsSatelliteSupported = supported;
5127         }
5128     }
5129 
handleEventSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId)5130     private void handleEventSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId) {
5131         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
5132             plogd("handleEventSelectedNbIotSatelliteSubscriptionChanged: "
5133                     + "carrierRoamingNbIotNtn flag is disabled");
5134             return;
5135         }
5136 
5137         plogd("handleEventSelectedNbIotSatelliteSubscriptionChanged: " + selectedSubId);
5138 
5139         List<ISelectedNbIotSatelliteSubscriptionCallback> deadCallersList = new ArrayList<>();
5140         mSelectedNbIotSatelliteSubscriptionChangedListeners.values().forEach(listener -> {
5141             try {
5142                 listener.onSelectedNbIotSatelliteSubscriptionChanged(selectedSubId);
5143             } catch (RemoteException e) {
5144                 logd("handleEventSelectedNbIotSatelliteSubscriptionChanged RemoteException: " + e);
5145                 deadCallersList.add(listener);
5146             }
5147         });
5148         deadCallersList.forEach(listener -> {
5149             mSelectedNbIotSatelliteSubscriptionChangedListeners.remove(listener.asBinder());
5150         });
5151     }
5152 
notifySatelliteSupportedStateChanged(boolean supported)5153     private void notifySatelliteSupportedStateChanged(boolean supported) {
5154         List<IBooleanConsumer> deadCallersList = new ArrayList<>();
5155         mSatelliteSupportedStateChangedListeners.values().forEach(listener -> {
5156             try {
5157                 listener.accept(supported);
5158             } catch (RemoteException e) {
5159                 plogd("handleSatelliteSupportedStateChangedEvent RemoteException: " + e);
5160                 deadCallersList.add(listener);
5161             }
5162         });
5163         deadCallersList.forEach(listener -> {
5164             mSatelliteSupportedStateChangedListeners.remove(listener.asBinder());
5165         });
5166     }
5167 
5168     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSettingsKeyForSatelliteMode(int val)5169     protected void setSettingsKeyForSatelliteMode(int val) {
5170         plogd("setSettingsKeyForSatelliteMode val: " + val);
5171         Settings.Global.putInt(mContext.getContentResolver(),
5172                     Settings.Global.SATELLITE_MODE_ENABLED, val);
5173     }
5174 
5175     /**
5176      * Allow screen rotation temporary in rotation locked foldable device.
5177      * <p>
5178      * Temporarily allow screen rotation user to catch satellite signals properly by UI guide in
5179      * emergency situations. Unlock the setting value so that the screen rotation is not locked, and
5180      * return it to the original value when the satellite service is finished.
5181      * <p>
5182      * Note that, only the unfolded screen will be temporarily allowed screen rotation.
5183      *
5184      * @param val {@link SATELLITE_MODE_ENABLED_TRUE} if satellite mode is enabled,
5185      *     {@link SATELLITE_MODE_ENABLED_FALSE} satellite mode is not enabled.
5186      */
5187     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSettingsKeyToAllowDeviceRotation(int val)5188     protected void setSettingsKeyToAllowDeviceRotation(int val) {
5189         // Only allows on a foldable device type.
5190         if (!isFoldable(mContext, mDeviceStates)) {
5191             logd("setSettingsKeyToAllowDeviceRotation(" + val + "), device was not a foldable");
5192             return;
5193         }
5194 
5195         switch (val) {
5196             case SATELLITE_MODE_ENABLED_TRUE:
5197                 mDeviceRotationLockToBackupAndRestore =
5198                         Settings.Secure.getString(mContentResolver,
5199                                 Settings.Secure.DEVICE_STATE_ROTATION_LOCK);
5200                 String unlockedRotationSettings = replaceDeviceRotationValue(
5201                         mDeviceRotationLockToBackupAndRestore == null
5202                                 ? "" : mDeviceRotationLockToBackupAndRestore,
5203                         Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED,
5204                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
5205                 Settings.Secure.putString(mContentResolver,
5206                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK, unlockedRotationSettings);
5207                 logd("setSettingsKeyToAllowDeviceRotation(TRUE), RotationSettings is changed"
5208                         + " from " + mDeviceRotationLockToBackupAndRestore
5209                         + " to " + unlockedRotationSettings);
5210                 break;
5211             case SATELLITE_MODE_ENABLED_FALSE:
5212                 if (mDeviceRotationLockToBackupAndRestore == null) {
5213                     break;
5214                 }
5215                 Settings.Secure.putString(mContentResolver,
5216                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
5217                         mDeviceRotationLockToBackupAndRestore);
5218                 logd("setSettingsKeyToAllowDeviceRotation(FALSE), RotationSettings is restored to"
5219                         + mDeviceRotationLockToBackupAndRestore);
5220                 mDeviceRotationLockToBackupAndRestore = "";
5221                 break;
5222             default:
5223                 loge("setSettingsKeyToAllowDeviceRotation(" + val + "), never reach here.");
5224                 break;
5225         }
5226     }
5227 
5228     /**
5229      * If the device type is foldable.
5230      *
5231      * @param context context
5232      * @param deviceStates list of {@link DeviceState}s provided from {@link DeviceStateManager}
5233      * @return {@code true} if device type is foldable. {@code false} for otherwise.
5234      */
5235     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isFoldable(Context context, List<DeviceState> deviceStates)5236     public boolean isFoldable(Context context, List<DeviceState> deviceStates) {
5237         if (android.hardware.devicestate.feature.flags.Flags.deviceStatePropertyMigration()) {
5238             return deviceStates.stream().anyMatch(deviceState -> deviceState.hasProperty(
5239                     PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)
5240                     || deviceState.hasProperty(
5241                     PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY));
5242         } else {
5243             return context.getResources().getIntArray(R.array.config_foldedDeviceStates).length > 0;
5244         }
5245     }
5246 
5247     /**
5248      * Replaces a value of given a target key with a new value in a string of key-value pairs.
5249      * <p>
5250      * Replaces the value corresponding to the target key with a new value. If the key value is not
5251      * found in the device rotation information, it is not replaced.
5252      *
5253      * @param deviceRotationValue Device rotation key values separated by colon(':').
5254      * @param targetKey The key of the new item caller wants to add.
5255      * @param newValue  The value of the new item caller want to add.
5256      * @return A new string where all the key-value pairs.
5257      */
replaceDeviceRotationValue( @onNull String deviceRotationValue, int targetKey, int newValue)5258     private static String replaceDeviceRotationValue(
5259             @NonNull String deviceRotationValue, int targetKey, int newValue) {
5260         // Use list of Key-Value pair
5261         List<Pair<Integer, Integer>> keyValuePairs = new ArrayList<>();
5262 
5263         String[] pairs = deviceRotationValue.split(":");
5264         if (pairs.length % 2 != 0) {
5265             // Return without modifying. The key-value may be incorrect if length is an odd number.
5266             loge("The length of key-value pair do not match. Return without modification.");
5267             return deviceRotationValue;
5268         }
5269 
5270         // collect into keyValuePairs
5271         for (int i = 0; i < pairs.length; i += 2) {
5272             try {
5273                 int key = Integer.parseInt(pairs[i]);
5274                 int value = Integer.parseInt(pairs[i + 1]);
5275                 keyValuePairs.add(new Pair<>(key, key == targetKey ? newValue : value));
5276             } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
5277                 // Return without modifying if got exception.
5278                 loge("got error while parsing key-value. Return without modification. e:" + e);
5279                 return deviceRotationValue;
5280             }
5281         }
5282 
5283         return keyValuePairs.stream()
5284                 .map(pair -> pair.first + ":" + pair.second) // Convert to "key:value" format
5285                 .collect(Collectors.joining(":")); // Join pairs with colons
5286     }
5287 
5288     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
areAllRadiosDisabled()5289     protected boolean areAllRadiosDisabled() {
5290         synchronized (mRadioStateLock) {
5291             if ((mDisableBTOnSatelliteEnabled && mBTStateEnabled)
5292                     || (mDisableNFCOnSatelliteEnabled && mNfcStateEnabled)
5293                     || (mDisableWifiOnSatelliteEnabled && mWifiStateEnabled)
5294                     || (mDisableUWBOnSatelliteEnabled && mUwbStateEnabled)) {
5295                 plogd("All radios are not disabled yet.");
5296                 return false;
5297             }
5298             plogd("All radios are disabled.");
5299             return true;
5300         }
5301     }
5302 
evaluateToSendSatelliteEnabledSuccess()5303     private void evaluateToSendSatelliteEnabledSuccess() {
5304         plogd("evaluateToSendSatelliteEnabledSuccess");
5305         synchronized (mSatelliteEnabledRequestLock) {
5306             if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null)
5307                     && mWaitingForRadioDisabled) {
5308                 plogd("Sending success to callback that sent enable satellite request");
5309                 synchronized (mIsSatelliteEnabledLock) {
5310                     mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite;
5311                 }
5312                 mSatelliteEnabledRequest.callback.accept(SATELLITE_RESULT_SUCCESS);
5313                 updateSatelliteEnabledState(
5314                         mSatelliteEnabledRequest.enableSatellite,
5315                         "EVENT_SET_SATELLITE_ENABLED_DONE");
5316                 setEmergencyMode(mSatelliteEnabledRequest.isEmergency);
5317                 if (mSatelliteEnabledRequest.enableSatellite
5318                         && !mSatelliteEnabledRequest.isEmergency) {
5319                     plogd("Starting pointingUI needFullscreenPointingUI=" + true
5320                             + "mIsDemoModeEnabled=" + mIsDemoModeEnabled + ", isEmergency="
5321                             + mSatelliteEnabledRequest.isEmergency);
5322                     mPointingAppController.startPointingUI(true, mIsDemoModeEnabled, false);
5323                 }
5324                 mSatelliteEnabledRequest = null;
5325                 mWaitingForRadioDisabled = false;
5326 
5327                 if (mSatelliteEnableAttributesUpdateRequest != null) {
5328                     sendRequestAsync(CMD_UPDATE_SATELLITE_ENABLE_ATTRIBUTES,
5329                             mSatelliteEnableAttributesUpdateRequest, null);
5330                 }
5331                 updateLastNotifiedNtnModeAndNotify(getSatellitePhone());
5332 
5333                 if (mFeatureFlags.satelliteExitP2pSessionOutsideGeofence()) {
5334                     evaluateDisablingP2pSession();
5335                 }
5336             }
5337         }
5338     }
5339 
resetSatelliteEnabledRequest()5340     private void resetSatelliteEnabledRequest() {
5341         plogd("resetSatelliteEnabledRequest");
5342         synchronized (mSatelliteEnabledRequestLock) {
5343             mSatelliteEnabledRequest = null;
5344             mWaitingForRadioDisabled = false;
5345         }
5346     }
5347 
resetSatelliteDisabledRequest()5348     private void resetSatelliteDisabledRequest() {
5349         plogd("resetSatelliteDisabledRequest");
5350         synchronized (mSatelliteEnabledRequestLock) {
5351             mSatelliteDisabledRequest = null;
5352             mWaitingForDisableSatelliteModemResponse = false;
5353             mWaitingForSatelliteModemOff = false;
5354         }
5355     }
5356 
5357     /**
5358      * Move to OFF state and clean up resources.
5359      *
5360      * @param resultCode The result code will be returned to requesting clients.
5361      */
5362     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
moveSatelliteToOffStateAndCleanUpResources( @atelliteManager.SatelliteResult int resultCode)5363     public void moveSatelliteToOffStateAndCleanUpResources(
5364             @SatelliteManager.SatelliteResult int resultCode) {
5365         plogd("moveSatelliteToOffStateAndCleanUpResources");
5366         setDemoModeEnabled(false);
5367         handlePersistentLoggingOnSessionEnd(mIsEmergency);
5368         setEmergencyMode(false);
5369         synchronized (mIsSatelliteEnabledLock) {
5370             mIsSatelliteEnabled = false;
5371         }
5372         setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE);
5373         setSettingsKeyToAllowDeviceRotation(SATELLITE_MODE_ENABLED_FALSE);
5374         abortSatelliteDisableRequest(resultCode);
5375         abortSatelliteEnableRequest(resultCode);
5376         abortSatelliteEnableAttributesUpdateRequest(resultCode);
5377         resetSatelliteEnabledRequest();
5378         resetSatelliteDisabledRequest();
5379         // TODO (b/361139260): Stop timer to wait for other radios off
5380         updateSatelliteEnabledState(
5381                 false, "moveSatelliteToOffStateAndCleanUpResources");
5382         selectBindingSatelliteSubscription(false);
5383         updateLastNotifiedNtnModeAndNotify(getSatellitePhone());
5384 
5385         sendMessage(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION));
5386         // Evaluate eligibility after satellite session is disabled
5387         sendMessage(obtainMessage(CMD_EVALUATE_CARRIER_ROAMING_NTN_ELIGIBILITY_CHANGE));
5388     }
5389 
setDemoModeEnabled(boolean enabled)5390     private void setDemoModeEnabled(boolean enabled) {
5391         mIsDemoModeEnabled = enabled;
5392         mDatagramController.setDemoMode(mIsDemoModeEnabled);
5393         plogd("setDemoModeEnabled: mIsDemoModeEnabled=" + mIsDemoModeEnabled);
5394     }
5395 
setEmergencyMode(boolean isEmergency)5396     private void setEmergencyMode(boolean isEmergency) {
5397         plogd("setEmergencyMode: mIsEmergency=" + mIsEmergency + ", isEmergency=" + isEmergency);
5398         if (mIsEmergency != isEmergency) {
5399             mIsEmergency = isEmergency;
5400             if (mSatelliteSessionController != null) {
5401                 mSatelliteSessionController.onEmergencyModeChanged(mIsEmergency);
5402             } else {
5403                 plogw("setEmergencyMode: mSatelliteSessionController is null");
5404             }
5405         }
5406     }
5407 
isMockModemAllowed()5408     private boolean isMockModemAllowed() {
5409         return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
5410     }
5411 
configureSatellitePlmnForCarrier(int subId)5412     private void configureSatellitePlmnForCarrier(int subId) {
5413         logd("configureSatellitePlmnForCarrier");
5414         Phone phone = SatelliteServiceUtils.getPhone(subId);
5415         if (phone == null) {
5416             ploge("configureSatellitePlmnForCarrier: phone is null for subId=" + subId);
5417             return;
5418         }
5419 
5420         List<String> allPlmnList = new ArrayList<>(getAllPlmnSet());
5421         phone.setSatellitePlmn(phone.getPhoneId(), getCarrierPlmnList(subId), allPlmnList,
5422                 obtainMessage(EVENT_SET_SATELLITE_PLMN_INFO_DONE));
5423     }
5424 
5425     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getAllPlmnSet()5426     protected Set<String> getAllPlmnSet() {
5427         Set<String> allPlmnSetFromSubInfo = new HashSet<>();
5428         int[] activeSubIdArray = mSubscriptionManagerService.getActiveSubIdList(true);
5429         for (int activeSubId : activeSubIdArray) {
5430             allPlmnSetFromSubInfo.addAll(getCarrierPlmnList(activeSubId));
5431             allPlmnSetFromSubInfo.addAll(getBarredPlmnList(activeSubId));
5432         }
5433         allPlmnSetFromSubInfo.addAll(mSatellitePlmnListFromOverlayConfig);
5434 
5435         if (mIgnorePlmnListFromStorage.get()) {
5436             // Do not use PLMN list from storage
5437             plogd("getAllPlmnList: allPlmnSetFromSubInfo=" + allPlmnSetFromSubInfo);
5438             return allPlmnSetFromSubInfo;
5439         }
5440 
5441         Set<String> allPlmnListFromStorage = getCarrierRoamingNtnAllSatellitePlmnSetFromStorage();
5442         if (!allPlmnListFromStorage.containsAll(allPlmnSetFromSubInfo)) {
5443             allPlmnListFromStorage.addAll(allPlmnSetFromSubInfo);
5444             persistCarrierRoamingNtnAllSatellitePlmnSet(allPlmnListFromStorage);
5445         }
5446 
5447         plogd("getAllPlmnList: " + allPlmnListFromStorage);
5448         return allPlmnListFromStorage;
5449     }
5450 
getCarrierPlmnList(int subId)5451     private List<String> getCarrierPlmnList(int subId) {
5452         synchronized (mSupportedSatelliteServicesLock) {
5453             return mMergedPlmnListPerCarrier.get(subId, new ArrayList<>()).stream().toList();
5454         }
5455     }
5456 
getBarredPlmnList(int subId)5457     private List<String> getBarredPlmnList(int subId) {
5458         synchronized (mSupportedSatelliteServicesLock) {
5459             return mEntitlementBarredPlmnListPerCarrier.get(
5460                     subId, new ArrayList<>()).stream().toList();
5461         }
5462     }
5463 
persistCarrierRoamingNtnAllSatellitePlmnSet(Set<String> allSatellitePlmnSet)5464     private void persistCarrierRoamingNtnAllSatellitePlmnSet(Set<String> allSatellitePlmnSet) {
5465         plogd("persistCarrierRoamingNtnAllSatellitePlmnSet");
5466         if (!loadSatelliteSharedPreferences()) return;
5467 
5468         if (mSharedPreferences == null) {
5469             ploge("persistCarrierRoamingNtnAllSatellitePlmnSet: mSharedPreferences is null");
5470         } else {
5471             try {
5472                 mSharedPreferences.edit().putStringSet(
5473                         CARRIER_ROAMING_NTN_ALL_SATELLITE_PLMN_SET_KEY, allSatellitePlmnSet)
5474                         .apply();
5475             } catch (Exception ex) {
5476                 plogd("persistCarrierRoamingNtnAllSatellitePlmnSet: ex=" + ex);
5477             }
5478 
5479             synchronized (mCarrierRoamingNtnAllSatellitePlmnSetLock) {
5480                 mCarrierRoamingNtnAllSatellitePlmnSet = allSatellitePlmnSet;
5481             }
5482         }
5483     }
5484 
getCarrierRoamingNtnAllSatellitePlmnSetFromStorage()5485     private Set<String> getCarrierRoamingNtnAllSatellitePlmnSetFromStorage() {
5486         synchronized (mCarrierRoamingNtnAllSatellitePlmnSetLock) {
5487             if (mCarrierRoamingNtnAllSatellitePlmnSet != null) {
5488                 plogd("getCarrierRoamingNtnAllSatellitePlmnSetFromStorage: "
5489                         + mCarrierRoamingNtnAllSatellitePlmnSet);
5490                 return mCarrierRoamingNtnAllSatellitePlmnSet;
5491             }
5492         }
5493 
5494         if (!loadSatelliteSharedPreferences()) return new HashSet<>();
5495 
5496         if (mSharedPreferences == null) {
5497             ploge("getCarrierRoamingNtnAllSatellitePlmnSetFromStorage: mSharedPreferences is null");
5498             return new HashSet<>();
5499         } else {
5500             Set<String> allSatellitePlmnSet = new HashSet<>();
5501             try {
5502                 allSatellitePlmnSet = mSharedPreferences.getStringSet(
5503                         CARRIER_ROAMING_NTN_ALL_SATELLITE_PLMN_SET_KEY, new HashSet<>());
5504             } catch (Exception ex) {
5505                 plogd("getCarrierRoamingNtnAllSatellitePlmnSetFromStorage: ex=" + ex);
5506             }
5507 
5508             synchronized (mCarrierRoamingNtnAllSatellitePlmnSetLock) {
5509                 mCarrierRoamingNtnAllSatellitePlmnSet = allSatellitePlmnSet;
5510                 plogd("getCarrierRoamingNtnAllSatellitePlmnSetFromStorage: "
5511                         + mCarrierRoamingNtnAllSatellitePlmnSet);
5512                 return mCarrierRoamingNtnAllSatellitePlmnSet;
5513             }
5514         }
5515     }
5516 
handleSetSatellitePlmnInfoDoneEvent(Message msg)5517     private void handleSetSatellitePlmnInfoDoneEvent(Message msg) {
5518         AsyncResult ar = (AsyncResult) msg.obj;
5519         SatelliteServiceUtils.getSatelliteError(ar, "handleSetSatellitePlmnInfoCmd");
5520     }
5521 
updateSupportedSatelliteServicesForActiveSubscriptions()5522     private void updateSupportedSatelliteServicesForActiveSubscriptions() {
5523         synchronized (mSupportedSatelliteServicesLock) {
5524             mSatelliteServicesSupportedByCarriersFromConfig.clear();
5525             mMergedPlmnListPerCarrier.clear();
5526             int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
5527             if (activeSubIds != null) {
5528                 for (int subId : activeSubIds) {
5529                     updateSupportedSatelliteServices(subId);
5530                     handleCarrierRoamingNtnAvailableServicesChanged(subId);
5531                 }
5532             } else {
5533                 loge("updateSupportedSatelliteServicesForActiveSubscriptions: "
5534                         + "activeSubIds is null");
5535             }
5536         }
5537     }
5538 
5539     /**
5540      * If the entitlementPlmnList exist then used it.
5541      * Otherwise, If the carrierPlmnList exist then used it.
5542      */
updatePlmnListPerCarrier(int subId)5543     private void updatePlmnListPerCarrier(int subId) {
5544         plogd("updatePlmnListPerCarrier: subId=" + subId);
5545         synchronized (mSupportedSatelliteServicesLock) {
5546             List<String> carrierPlmnList, entitlementPlmnList;
5547             if (getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
5548                     false)) {
5549                 entitlementPlmnList = mEntitlementPlmnListPerCarrier.get(subId,
5550                         new ArrayList<>()).stream().toList();
5551                 plogd("updatePlmnListPerCarrier: entitlementPlmnList="
5552                         + String.join(",", entitlementPlmnList)
5553                         + " size=" + entitlementPlmnList.size());
5554                 if (!entitlementPlmnList.isEmpty()) {
5555                     mMergedPlmnListPerCarrier.put(subId, entitlementPlmnList);
5556                     plogd("mMergedPlmnListPerCarrier is updated by Entitlement");
5557                     mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(subId,
5558                             SatelliteConstants.CONFIG_DATA_SOURCE_ENTITLEMENT);
5559                     return;
5560                 }
5561             }
5562 
5563             SatelliteConfig satelliteConfig = getSatelliteConfig();
5564             if (satelliteConfig != null) {
5565                 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
5566                 int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
5567                 List<String> plmnList = satelliteConfig.getAllSatellitePlmnsForCarrier(carrierId);
5568                 if (!plmnList.isEmpty()) {
5569                     plogd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : "
5570                             + String.join(",", plmnList));
5571                     mMergedPlmnListPerCarrier.put(subId, plmnList);
5572                     mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(subId,
5573                             SatelliteConstants.CONFIG_DATA_SOURCE_CONFIG_UPDATER);
5574                     return;
5575                 }
5576             }
5577 
5578             if (mSatelliteServicesSupportedByCarriersFromConfig.containsKey(subId)
5579                     && mSatelliteServicesSupportedByCarriersFromConfig.get(subId) != null) {
5580                 carrierPlmnList =
5581                         mSatelliteServicesSupportedByCarriersFromConfig.get(subId).keySet()
5582                                 .stream().toList();
5583                 plogd("mMergedPlmnListPerCarrier is updated by carrier config: "
5584                         + String.join(",", carrierPlmnList));
5585                 mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(subId,
5586                         SatelliteConstants.CONFIG_DATA_SOURCE_CARRIER_CONFIG);
5587             } else {
5588                 carrierPlmnList = new ArrayList<>();
5589                 plogd("Empty mMergedPlmnListPerCarrier");
5590             }
5591             mMergedPlmnListPerCarrier.put(subId, carrierPlmnList);
5592         }
5593     }
5594 
updateSupportedSatelliteServices(int subId)5595     private void updateSupportedSatelliteServices(int subId) {
5596         plogd("updateSupportedSatelliteServices with subId " + subId);
5597         synchronized (mSupportedSatelliteServicesLock) {
5598             SatelliteConfig satelliteConfig = getSatelliteConfig();
5599 
5600             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
5601             int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
5602 
5603             if (satelliteConfig != null) {
5604                 Map<String, Set<Integer>> supportedServicesPerPlmn =
5605                         satelliteConfig.getSupportedSatelliteServices(carrierId);
5606                 if (!supportedServicesPerPlmn.isEmpty()) {
5607                     mSatelliteServicesSupportedByCarriersFromConfig.put(subId,
5608                             supportedServicesPerPlmn);
5609                     plogd("updateSupportedSatelliteServices using ConfigUpdater, "
5610                             + "supportedServicesPerPlmn = " + supportedServicesPerPlmn.size());
5611                     updatePlmnListPerCarrier(subId);
5612                     return;
5613                 } else {
5614                     plogd("supportedServicesPerPlmn is empty");
5615                 }
5616             }
5617 
5618             mSatelliteServicesSupportedByCarriersFromConfig.put(
5619                     subId, readSupportedSatelliteServicesFromCarrierConfig(subId));
5620             updatePlmnListPerCarrier(subId);
5621             plogd("updateSupportedSatelliteServices using carrier config");
5622         }
5623     }
5624 
5625     @NonNull
readSatellitePlmnsFromOverlayConfig()5626     private List<String> readSatellitePlmnsFromOverlayConfig() {
5627         String[] devicePlmns = readStringArrayFromOverlayConfig(
5628                 R.array.config_satellite_providers);
5629         return Arrays.stream(devicePlmns).toList();
5630     }
5631 
5632     @NonNull
readSupportedSatelliteServicesFromCarrierConfig(int subId)5633     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) {
5634         PersistableBundle config = getPersistableBundle(subId);
5635         return SatelliteServiceUtils.parseSupportedSatelliteServices(
5636                 config.getPersistableBundle(
5637                         KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
5638     }
5639 
5640     @NonNull
readRegionalSatelliteEarfcnsFromCarrierConfig(int subId)5641     private Map<String, Set<Integer>> readRegionalSatelliteEarfcnsFromCarrierConfig(int subId) {
5642         PersistableBundle config = getPersistableBundle(subId);
5643         return SatelliteServiceUtils.parseRegionalSatelliteEarfcns(
5644                 config.getPersistableBundle(KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE));
5645     }
5646 
getConfigForSubId(int subId)5647     @NonNull private PersistableBundle getConfigForSubId(int subId) {
5648         PersistableBundle config = null;
5649         if (mCarrierConfigManager != null) {
5650             try {
5651                 config = mCarrierConfigManager.getConfigForSubId(subId,
5652                         KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
5653                         KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
5654                         KEY_SATELLITE_DISPLAY_NAME_STRING,
5655                         KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL,
5656                         KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT,
5657                         KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
5658                         KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
5659                         KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
5660                         KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
5661                         KEY_SATELLITE_ESOS_SUPPORTED_BOOL,
5662                         KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL,
5663                         KEY_SATELLITE_NIDD_APN_NAME_STRING,
5664                         KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
5665                         KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT,
5666                         KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT,
5667                         KEY_SATELLITE_ROAMING_SCREEN_OFF_INACTIVITY_TIMEOUT_SEC_INT,
5668                         KEY_SATELLITE_ROAMING_P2P_SMS_INACTIVITY_TIMEOUT_SEC_INT,
5669                         KEY_SATELLITE_ROAMING_ESOS_INACTIVITY_TIMEOUT_SEC_INT,
5670                         KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE_BYTES_INT,
5671                         KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY,
5672                         KEY_REGIONAL_SATELLITE_EARFCN_BUNDLE,
5673                         KEY_SATELLITE_DATA_SUPPORT_MODE_INT,
5674                         KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT
5675                 );
5676             } catch (Exception e) {
5677                 logw("getConfigForSubId: " + e);
5678             }
5679         }
5680         if (config == null || config.isEmpty()) {
5681             config = CarrierConfigManager.getDefaultConfig();
5682         }
5683         return config;
5684     }
5685 
handleCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId)5686     private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId,
5687             int specificCarrierId) {
5688         plogd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId("
5689                 + subId + "), carrierId(" + carrierId + "), specificCarrierId("
5690                 + specificCarrierId + ")");
5691         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
5692             return;
5693         }
5694 
5695         getSatelliteEnabledForCarrierAtModem(subId);
5696         updateCarrierConfig(subId);
5697         updateSatelliteESOSSupported(subId);
5698         updateSatelliteProvisionedStatePerSubscriberId();
5699         updateEntitlementPlmnListPerCarrier(subId);
5700         updateSupportedSatelliteServicesForActiveSubscriptions();
5701         processNewCarrierConfigData(subId);
5702         resetCarrierRoamingSatelliteModeParams(subId);
5703         evaluateCarrierRoamingNtnEligibilityChange();
5704         sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
5705                 mEvaluateEsosProfilesPrioritizationDurationMillis);
5706         updateRegionalSatelliteEarfcns(subId);
5707     }
5708 
getSatelliteEnabledForCarrierAtModem(int subId)5709     private void getSatelliteEnabledForCarrierAtModem(int subId) {
5710         Phone phone = SatelliteServiceUtils.getPhone(subId);
5711         synchronized (mIsSatelliteEnabledLock) {
5712             if (!mIsSatelliteAttachEnabledForCarrierArrayPerSub.containsKey(subId)) {
5713                 // Get enabled status from modem for new subscription
5714                 sendRequestAsync(CMD_GET_SATELLITE_ENABLED_FOR_CARRIER, null, phone);
5715             }
5716         }
5717     }
5718 
5719     // imsi, msisdn, default sms subId change
handleSubscriptionsChanged()5720     private void handleSubscriptionsChanged() {
5721         sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
5722                 mEvaluateEsosProfilesPrioritizationDurationMillis);
5723     }
5724 
processNewCarrierConfigData(int subId)5725     private void processNewCarrierConfigData(int subId) {
5726         updateRestrictReasonForEntitlementPerCarrier(subId);
5727         configureSatellitePlmnForCarrier(subId);
5728         evaluateEnablingSatelliteForCarrier(subId,
5729                 SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, null);
5730     }
5731 
5732     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
updateCarrierConfig(int subId)5733     protected void updateCarrierConfig(int subId) {
5734         synchronized (mCarrierConfigArrayLock) {
5735             mCarrierConfigArray.put(subId, getConfigForSubId(subId));
5736         }
5737     }
5738 
5739     /**
5740      * If there is no cached entitlement plmn list, read it from the db and use it if it is not an
5741      * empty list.
5742      */
updateEntitlementPlmnListPerCarrier(int subId)5743     private void updateEntitlementPlmnListPerCarrier(int subId) {
5744         if (!getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false)) {
5745             plogd("don't support entitlement");
5746             return;
5747         }
5748 
5749         synchronized (mSupportedSatelliteServicesLock) {
5750             if (mEntitlementPlmnListPerCarrier.indexOfKey(subId) < 0) {
5751                 plogd("updateEntitlementPlmnListPerCarrier: no correspondent cache, load from "
5752                         + "persist storage");
5753                 List<String> entitlementPlmnList =
5754                         mSubscriptionManagerService.getSatelliteEntitlementPlmnList(subId);
5755                 if (entitlementPlmnList.isEmpty()) {
5756                     plogd("updateEntitlementPlmnListPerCarrier: read empty list");
5757                     return;
5758                 }
5759                 plogd("updateEntitlementPlmnListPerCarrier: entitlementPlmnList=" + String.join(",",
5760                         entitlementPlmnList));
5761                 mEntitlementPlmnListPerCarrier.put(subId, entitlementPlmnList);
5762             }
5763 
5764             if (mEntitlementBarredPlmnListPerCarrier.indexOfKey(subId) < 0) {
5765                 plogd("updateEntitlementBarredPlmnList: no correspondent cache, load from "
5766                         + "persist storage");
5767                 List<String> entitlementBarredPlmnList =
5768                         mSubscriptionManagerService.getSatelliteEntitlementBarredPlmnList(subId);
5769                 if (entitlementBarredPlmnList.isEmpty()) {
5770                     plogd("updateEntitlementBarredPlmnList: read empty list");
5771                     return;
5772                 }
5773                 plogd("updateEntitlementBarredPlmnList: entitlementBarredPlmnList=" + String.join(
5774                         ",", entitlementBarredPlmnList));
5775                 mEntitlementBarredPlmnListPerCarrier.put(subId, entitlementBarredPlmnList);
5776             }
5777 
5778             if (mEntitlementDataPlanMapPerCarrier.indexOfKey(subId) < 0) {
5779                 plogd("updateEntitlementDataPlanForPlmns: no correspondent cache, load from "
5780                         + "persist storage");
5781                 Map<String, Integer> entitlementDataPlanForPlmns =
5782                         mSubscriptionManagerService.getSatelliteEntitlementDataPlanForPlmns(subId);
5783                 if (entitlementDataPlanForPlmns.isEmpty()) {
5784                     plogd("updateEntitlementBarredPlmnList: read empty list");
5785                     return;
5786                 }
5787                 plogd("updateEntitlementDataPlanForPlmns: entitlementDataPlanForPlmns="
5788                         + entitlementDataPlanForPlmns);
5789                 mEntitlementDataPlanMapPerCarrier.put(subId, entitlementDataPlanForPlmns);
5790             }
5791 
5792             if (mEntitlementServiceTypeMapPerCarrier.indexOfKey(subId) < 0) {
5793                 plogd("updateEntitlementTypeMapPerCarrier: no correspondent cache, load from "
5794                         + "persist storage");
5795                 Map<String, List<Integer>> entitlementTypeMapPerCarrier =
5796                         mSubscriptionManagerService.getSatelliteEntitlementPlmnServiceTypeMap(
5797                                 subId);
5798                 if (entitlementTypeMapPerCarrier.isEmpty()) {
5799                     plogd("updateEntitlementTypeMapPerCarrier: read empty list");
5800                     return;
5801                 }
5802                 plogd("updateEntitlementTypeMapPerCarrier: entitlementTypeMapPerCarrier="
5803                         + entitlementTypeMapPerCarrier);
5804                 mEntitlementServiceTypeMapPerCarrier.put(subId, entitlementTypeMapPerCarrier);
5805             }
5806 
5807             if (mEntitlementDataServicePolicyMapPerCarrier.indexOfKey(subId) < 0) {
5808                 plogd("updateEntitlementDataServicePolicy: no correspondent cache, load from "
5809                         + "persist storage");
5810                 Map<String, Integer> entitlementDataServicePolicy =
5811                         mSubscriptionManagerService.getSatelliteEntitlementPlmnDataServicePolicy(
5812                                 subId);
5813                 if (entitlementDataServicePolicy.isEmpty()) {
5814                     plogd("updateEntitlementDataServicePolicy: read empty list");
5815                     return;
5816                 }
5817                 plogd("updateEntitlementDataServicePolicy: entitlementDataServicePolicy="
5818                         + entitlementDataServicePolicy);
5819                 mEntitlementDataServicePolicyMapPerCarrier.put(subId, entitlementDataServicePolicy);
5820             }
5821 
5822             if (mEntitlementVoiceServicePolicyMapPerCarrier.indexOfKey(subId) < 0) {
5823                 plogd("updateEntitlementVoiceServicePolicy: no correspondent cache, load from "
5824                         + "persist storage");
5825                 Map<String, Integer> entitlementVoiceServicePolicy =
5826                         mSubscriptionManagerService.getSatelliteEntitlementPlmnVoiceServicePolicy(
5827                                 subId);
5828                 if (entitlementVoiceServicePolicy.isEmpty()) {
5829                     plogd("updateEntitlementVoiceServicePolicy: read empty list");
5830                     return;
5831                 }
5832                 plogd("updateEntitlementVoiceServicePolicy: entitlementVoiceServicePolicy="
5833                         + entitlementVoiceServicePolicy);
5834                 mEntitlementVoiceServicePolicyMapPerCarrier.put(subId,
5835                         entitlementVoiceServicePolicy);
5836             }
5837         }
5838     }
5839 
5840     /**
5841      * Update the value of SimInfo.COLUMN_SATELLITE_ESOS_SUPPORTED stored in the database based
5842      * on the value in the carrier config.
5843      */
updateSatelliteESOSSupported(int subId)5844     private void updateSatelliteESOSSupported(int subId) {
5845         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
5846             return;
5847         }
5848 
5849         boolean isSatelliteESosSupportedFromDB =
5850                 mSubscriptionManagerService.getSatelliteESOSSupported(subId);
5851         boolean isSatelliteESosSupportedFromCarrierConfig = getConfigForSubId(subId).getBoolean(
5852                 KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false);
5853         if (isSatelliteESosSupportedFromDB != isSatelliteESosSupportedFromCarrierConfig) {
5854             mSubscriptionManagerService.setSatelliteESOSSupported(subId,
5855                     isSatelliteESosSupportedFromCarrierConfig);
5856             logd("updateSatelliteESOSSupported: " + isSatelliteESosSupportedFromCarrierConfig);
5857         }
5858     }
5859 
5860     /** If the provision state per subscriberId for the cached is not exist, check the database for
5861      * the corresponding value and use it. */
updateSatelliteProvisionedStatePerSubscriberId()5862     protected void updateSatelliteProvisionedStatePerSubscriberId() {
5863         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
5864             return;
5865         }
5866 
5867         List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList(
5868                 mContext.getOpPackageName(), mContext.getAttributionTag());
5869         for (SubscriptionInfo info : allSubInfos) {
5870             int subId = info.getSubscriptionId();
5871             Pair<String, Integer> subscriberIdPair = getSubscriberIdAndType(
5872                     mSubscriptionManagerService.getSubscriptionInfo(subId));
5873             String subscriberId = subscriberIdPair.first;
5874             synchronized (mSatelliteTokenProvisionedLock) {
5875                 if (mProvisionedSubscriberId.get(subscriberId) == null) {
5876                     boolean Provisioned = mSubscriptionManagerService
5877                             .isSatelliteProvisionedForNonIpDatagram(subId);
5878                     if (Provisioned) {
5879                         mProvisionedSubscriberId.put(subscriberId, true);
5880                         logd("updateSatelliteProvisionStatePerSubscriberId: "
5881                                 + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, subscriberId)
5882                                 + " set true");
5883                     }
5884                 }
5885             }
5886         }
5887         // Need to update the provision status of the device
5888         updateCachedDeviceProvisionStatus();
5889     }
5890 
5891     @NonNull
readStringArrayFromOverlayConfig(@rrayRes int id)5892     private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) {
5893         String[] strArray = null;
5894         try {
5895             strArray = mContext.getResources().getStringArray(id);
5896         } catch (Resources.NotFoundException ex) {
5897             ploge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex);
5898         }
5899         if (strArray == null) {
5900             strArray = new String[0];
5901         }
5902         return strArray;
5903     }
5904 
isSatelliteSupportedViaCarrier(int subId)5905     private boolean isSatelliteSupportedViaCarrier(int subId) {
5906         return getConfigForSubId(subId)
5907                 .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
5908     }
5909 
5910     /**
5911      * Return whether the device support P2P SMS mode from carrier config.
5912      *
5913      * @param subId Associated subscription ID
5914      */
5915     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
isSatelliteRoamingP2pSmSSupported(int subId)5916     public boolean isSatelliteRoamingP2pSmSSupported(int subId) {
5917         return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ROAMING_P2P_SMS_SUPPORTED_BOOL);
5918     }
5919 
5920     /**
5921      * Return whether the device support ESOS mode from carrier config.
5922      *
5923      * @param subId Associated subscription ID
5924      */
5925     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
isSatelliteEsosSupported(int subId)5926     public boolean isSatelliteEsosSupported(int subId) {
5927         return getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
5928     }
5929 
5930     /**
5931      * Return whether the device allows to turn off satellite session for emergency call.
5932      *
5933      * @param subId Associated subscription ID
5934      */
5935     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
turnOffSatelliteSessionForEmergencyCall(int subId)5936     public boolean turnOffSatelliteSessionForEmergencyCall(int subId) {
5937         return getConfigForSubId(subId).getBoolean(
5938                 KEY_SATELLITE_ROAMING_TURN_OFF_SESSION_FOR_EMERGENCY_CALL_BOOL);
5939     }
5940 
getCarrierRoamingNtnConnectType(int subId)5941     private int getCarrierRoamingNtnConnectType(int subId) {
5942         return getConfigForSubId(subId).getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT);
5943     }
5944 
getCarrierRoamingNtnEmergencyCallToSatelliteHandoverType(int subId)5945     protected int getCarrierRoamingNtnEmergencyCallToSatelliteHandoverType(int subId) {
5946         return getConfigForSubId(subId).getInt(
5947                 KEY_CARRIER_ROAMING_NTN_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_INT);
5948     }
5949 
5950     @CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE
getCarrierSatelliteDataSupportedModeFromConfig(int subId)5951     private int getCarrierSatelliteDataSupportedModeFromConfig(int subId) {
5952         return getConfigForSubId(subId).getInt(KEY_SATELLITE_DATA_SUPPORT_MODE_INT);
5953     }
5954 
5955     /**
5956      * Satellite notification display restriction timeout. Default value is 7 days in millis.
5957      * @param subId : subscription Id.
5958      * @return : Notification throttle timeout in millis.
5959      */
getNotificationDisplayThrottleTimeout(int subId)5960     private long getNotificationDisplayThrottleTimeout(int subId) {
5961         if (Flags.starlinkDataBugfix()) {
5962             return getConfigForSubId(subId).getLong(
5963                     KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT);
5964         } else {
5965             return TimeUnit.DAYS.toMillis(7);
5966         }
5967     }
5968 
5969     /**
5970      * Check if satellite attach is enabled by user for the carrier associated with the
5971      * {@code subId}.
5972      *
5973      * @param subId Subscription ID.
5974      *
5975      * @return Returns {@code true} if satellite attach for carrier is enabled by user,
5976      * {@code false} otherwise.
5977      */
isSatelliteAttachEnabledForCarrierByUser(int subId)5978     private boolean isSatelliteAttachEnabledForCarrierByUser(int subId) {
5979         synchronized (mIsSatelliteEnabledLock) {
5980             Set<Integer> cachedRestrictionSet =
5981                     mSatelliteAttachRestrictionForCarrierArray.get(subId);
5982             if (cachedRestrictionSet != null) {
5983                 return !cachedRestrictionSet.contains(
5984                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER);
5985             } else {
5986                 plogd("isSatelliteAttachEnabledForCarrierByUser() no correspondent cache, "
5987                         + "load from persist storage");
5988                 try {
5989                     String enabled =
5990                             mSubscriptionManagerService.getSubscriptionProperty(subId,
5991                                     SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
5992                                     mContext.getOpPackageName(), mContext.getAttributionTag());
5993 
5994                     if (enabled == null) {
5995                         ploge("isSatelliteAttachEnabledForCarrierByUser: invalid subId, subId="
5996                                 + subId);
5997                         return false;
5998                     }
5999 
6000                     if (enabled.isEmpty()) {
6001                         ploge("isSatelliteAttachEnabledForCarrierByUser: no data for subId(" + subId
6002                                 + ")");
6003                         return false;
6004                     }
6005 
6006                     synchronized (mIsSatelliteEnabledLock) {
6007                         boolean result = enabled.equals("1");
6008                         if (!result) {
6009                             mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>());
6010                             mSatelliteAttachRestrictionForCarrierArray.get(subId).add(
6011                                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER);
6012                         }
6013                         return result;
6014                     }
6015                 } catch (IllegalArgumentException | SecurityException ex) {
6016                     ploge("isSatelliteAttachEnabledForCarrierByUser: ex=" + ex);
6017                     return false;
6018                 }
6019             }
6020         }
6021     }
6022 
6023     /**
6024      * Check whether there is any reason to restrict satellite communication for the carrier
6025      * associated with the {@code subId}.
6026      *
6027      * @param subId Subscription ID
6028      * @return {@code true} when there is at least on reason, {@code false} otherwise.
6029      */
hasReasonToRestrictSatelliteCommunicationForCarrier(int subId)6030     private boolean hasReasonToRestrictSatelliteCommunicationForCarrier(int subId) {
6031         synchronized (mIsSatelliteEnabledLock) {
6032             return !mSatelliteAttachRestrictionForCarrierArray
6033                     .getOrDefault(subId, Collections.emptySet()).isEmpty();
6034         }
6035     }
6036 
updateRestrictReasonForEntitlementPerCarrier(int subId)6037     private void updateRestrictReasonForEntitlementPerCarrier(int subId) {
6038         if (!getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false)) {
6039             plogd("don't support entitlement");
6040             return;
6041         }
6042 
6043         IIntegerConsumer callback = new IIntegerConsumer.Stub() {
6044             @Override
6045             public void accept(int result) {
6046                 plogd("updateRestrictReasonForEntitlementPerCarrier:" + result);
6047             }
6048         };
6049         synchronized (mSupportedSatelliteServicesLock) {
6050             if (mSatelliteEntitlementStatusPerCarrier.indexOfKey(subId) < 0) {
6051                 plogd("updateRestrictReasonForEntitlementPerCarrier: no correspondent cache, "
6052                         + "load from persist storage");
6053                 String entitlementStatus = null;
6054                 try {
6055                     entitlementStatus =
6056                             mSubscriptionManagerService.getSubscriptionProperty(subId,
6057                                     SATELLITE_ENTITLEMENT_STATUS, mContext.getOpPackageName(),
6058                                     mContext.getAttributionTag());
6059                 } catch (IllegalArgumentException | SecurityException e) {
6060                     ploge("updateRestrictReasonForEntitlementPerCarrier, e=" + e);
6061                 }
6062 
6063                 if (entitlementStatus == null) {
6064                     ploge("updateRestrictReasonForEntitlementPerCarrier: invalid subId, subId="
6065                             + subId + " set to default value");
6066                     entitlementStatus = "0";
6067                 }
6068 
6069                 if (entitlementStatus.isEmpty()) {
6070                     ploge("updateRestrictReasonForEntitlementPerCarrier: no data for subId(" + subId
6071                             + "). set to default value");
6072                     entitlementStatus = "0";
6073                 }
6074                 boolean result = entitlementStatus.equals("1");
6075                 mSatelliteEntitlementStatusPerCarrier.put(subId, result);
6076                 mCarrierRoamingSatelliteControllerStats.reportIsDeviceEntitled(subId, result);
6077                 if (hasMessages(EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT)) {
6078                     removeMessages(EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT);
6079                     sendMessageDelayed(obtainMessage(
6080                                     EVENT_WAIT_FOR_REPORT_ENTITLED_TO_MERTICS_HYSTERESIS_TIMED_OUT),
6081                             WAIT_FOR_REPORT_ENTITLED_MERTICS_TIMEOUT_MILLIS);
6082                 }
6083             }
6084 
6085             if (!mSatelliteEntitlementStatusPerCarrier.get(subId, false)) {
6086                 addAttachRestrictionForCarrier(subId,
6087                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
6088             }
6089         }
6090     }
6091 
6092     /**
6093      * Save user setting for enabling satellite attach for the carrier associated with the
6094      * {@code subId} to persistent storage.
6095      *
6096      * @param subId Subscription ID.
6097      *
6098      * @return {@code true} if persist successful, {@code false} otherwise.
6099      */
6100     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
persistSatelliteAttachEnabledForCarrierSetting(int subId)6101     protected boolean persistSatelliteAttachEnabledForCarrierSetting(int subId) {
6102         plogd("persistSatelliteAttachEnabledForCarrierSetting");
6103         if (!isValidSubscriptionId(subId)) {
6104             ploge("persistSatelliteAttachEnabledForCarrierSetting: subId is not valid,"
6105                     + " subId=" + subId);
6106             return false;
6107         }
6108 
6109         synchronized (mIsSatelliteEnabledLock) {
6110             try {
6111                 mSubscriptionManagerService.setSubscriptionProperty(subId,
6112                         SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
6113                         mSatelliteAttachRestrictionForCarrierArray.get(subId)
6114                                 .contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)
6115                                 ? "0" : "1");
6116             } catch (IllegalArgumentException | SecurityException ex) {
6117                 ploge("persistSatelliteAttachEnabledForCarrierSetting, ex=" + ex);
6118                 return false;
6119             }
6120         }
6121         return true;
6122     }
6123 
6124     /**
6125      * Evaluate whether satellite attach for carrier should be restricted.
6126      *
6127      * @param subId Subscription Id to evaluate for.
6128      * @return {@code true} satellite attach is restricted, {@code false} otherwise.
6129      */
isSatelliteRestrictedForCarrier(int subId)6130     private boolean isSatelliteRestrictedForCarrier(int subId) {
6131         return !isSatelliteAttachEnabledForCarrierByUser(subId)
6132                 || hasReasonToRestrictSatelliteCommunicationForCarrier(subId);
6133     }
6134 
6135     /**
6136      * Check whether satellite is enabled for carrier at modem.
6137      *
6138      * @param subId subscription ID
6139      * @return {@code true} if satellite modem is enabled, {@code false} otherwise.
6140      */
6141     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isSatelliteEnabledForCarrierAtModem(int subId)6142     public boolean isSatelliteEnabledForCarrierAtModem(int subId) {
6143         synchronized (mIsSatelliteEnabledLock) {
6144             return mIsSatelliteAttachEnabledForCarrierArrayPerSub.getOrDefault(subId, false);
6145         }
6146     }
6147 
6148     /**
6149      * Evaluate whether satellite modem for carrier should be enabled or not.
6150      * <p>
6151      * Satellite will be enabled only when the following conditions are met:
6152      * <ul>
6153      * <li>Users want to enable it.</li>
6154      * <li>There is no satellite communication restriction, which is added by
6155      * {@link #addAttachRestrictionForCarrier(int, int, IIntegerConsumer)}</li>
6156      * <li>The carrier config {@link
6157      * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
6158      * {@code true}.</li>
6159      * </ul>
6160      *
6161      * @param subId Subscription Id for evaluate for.
6162      * @param callback The callback for getting the result of enabling satellite.
6163      */
evaluateEnablingSatelliteForCarrier(int subId, int reason, @Nullable Consumer<Integer> callback)6164     private void evaluateEnablingSatelliteForCarrier(int subId, int reason,
6165             @Nullable Consumer<Integer> callback) {
6166         if (callback == null) {
6167             callback = errorCode -> plogd("evaluateEnablingSatelliteForCarrier: "
6168                     + "SetSatelliteAttachEnableForCarrier error code =" + errorCode);
6169         }
6170 
6171         Phone phone = SatelliteServiceUtils.getPhone(subId);
6172         if (phone == null) {
6173             ploge("evaluateEnablingSatelliteForCarrier: phone is null for subId=" + subId);
6174             callback.accept(SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
6175             return;
6176         }
6177 
6178         /* Request to enable or disable the satellite in the cellular modem only when the desired
6179         state and the current state are different. */
6180         boolean isSatelliteExpectedToBeEnabled = !isSatelliteRestrictedForCarrier(subId)
6181                 && isSatelliteSupportedViaCarrier(subId);
6182         boolean isSatelliteEnabledForCarrierAtModem = isSatelliteEnabledForCarrierAtModem(
6183                 phone.getSubId());
6184         plogd("evaluateEnablingSatelliteForCarrier: subId=" + subId + " reason=" + reason
6185                 + " isSatelliteExpectedToBeEnabled=" + isSatelliteExpectedToBeEnabled
6186                 + " isSatelliteEnabledForCarrierAtModem=" + isSatelliteEnabledForCarrierAtModem);
6187 
6188         if (isSatelliteExpectedToBeEnabled != isSatelliteEnabledForCarrierAtModem) {
6189             int simSlot = SubscriptionManager.getSlotIndex(subId);
6190             RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
6191                     new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId,
6192                             reason, callback);
6193             SatelliteControllerHandlerRequest request =
6194                     new SatelliteControllerHandlerRequest(argument,
6195                             SatelliteServiceUtils.getPhone(subId));
6196             Message onCompleted = obtainMessage(
6197                     EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE, request);
6198             phone.setSatelliteEnabledForCarrier(simSlot,
6199                     isSatelliteExpectedToBeEnabled, onCompleted);
6200         } else {
6201             callback.accept(SATELLITE_RESULT_SUCCESS);
6202         }
6203     }
6204 
evaluateOemSatelliteRequestAllowed( boolean isProvisionRequired)6205     @SatelliteManager.SatelliteResult private int evaluateOemSatelliteRequestAllowed(
6206             boolean isProvisionRequired) {
6207         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
6208             plogd("evaluateOemSatelliteRequestAllowed: satellite service is not supported");
6209             return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
6210         }
6211 
6212         Boolean satelliteSupported = isSatelliteSupportedViaOemInternal();
6213         if (satelliteSupported == null) {
6214             plogd("evaluateOemSatelliteRequestAllowed: satelliteSupported is null");
6215             return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
6216         }
6217         if (!satelliteSupported) {
6218             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
6219         }
6220 
6221         if (isProvisionRequired) {
6222             Boolean satelliteProvisioned = isDeviceProvisioned();
6223             if (satelliteProvisioned == null) {
6224                 plogd("evaluateOemSatelliteRequestAllowed: satelliteProvisioned is null");
6225                 return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
6226             }
6227             if (!satelliteProvisioned) {
6228                 plogd("evaluateOemSatelliteRequestAllowed: satellite service is not provisioned");
6229                 return SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED;
6230             }
6231         }
6232 
6233         return SATELLITE_RESULT_SUCCESS;
6234     }
6235 
6236     /**
6237      * Returns the non-terrestrial network radio technology that the satellite modem currently
6238      * supports. If multiple technologies are available, returns the first supported technology.
6239      */
6240     @VisibleForTesting
getSupportedNtnRadioTechnology()6241     protected @SatelliteManager.NTRadioTechnology int getSupportedNtnRadioTechnology() {
6242         SatelliteCapabilities satelliteCapabilities = getSatelliteCapabilities();
6243         if (satelliteCapabilities != null) {
6244             return satelliteCapabilities.getSupportedRadioTechnologies()
6245                     .stream().findFirst().orElse(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN);
6246         }
6247         return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
6248     }
6249 
6250     /**
6251      * Returns a list of messaging apps that support satellite.
6252      */
getSatelliteSupportedMsgApps(int subId)6253     @NonNull public List<String> getSatelliteSupportedMsgApps(int subId) {
6254         String[] satelliteSupportedMsgApps = getConfigForSubId(subId)
6255                 .getStringArray(KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY);
6256 
6257         return satelliteSupportedMsgApps != null
6258                 ? List.of(satelliteSupportedMsgApps) : Collections.emptyList();
6259     }
6260 
sendErrorAndReportSessionMetrics(@atelliteManager.SatelliteResult int error, Consumer<Integer> result)6261     private void sendErrorAndReportSessionMetrics(@SatelliteManager.SatelliteResult int error,
6262             Consumer<Integer> result) {
6263         result.accept(error);
6264         mSessionMetricsStats.setInitializationResult(error)
6265                 .setSatelliteTechnology(getSupportedNtnRadioTechnology())
6266                 .setIsDemoMode(mIsDemoModeEnabled)
6267                 .setCarrierId(getSatelliteCarrierId())
6268                 .setIsNtnOnlyCarrier(isNtnOnlyCarrier())
6269                 .reportSessionMetrics();
6270         mSessionStartTimeStamp = 0;
6271         mSessionProcessingTimeStamp = 0;
6272     }
6273 
isNtnOnlyCarrier()6274     public boolean isNtnOnlyCarrier() {
6275         synchronized (mSatelliteTokenProvisionedLock) {
6276             if (mSelectedSatelliteSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
6277                 return false;
6278             }
6279             return mSelectedSatelliteSubId == getNtnOnlySubscriptionId();
6280         }
6281     }
6282 
registerForServiceStateChanged()6283     private void registerForServiceStateChanged() {
6284         for (Phone phone : PhoneFactory.getPhones()) {
6285             phone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
6286         }
6287     }
6288 
registerForSignalStrengthChanged()6289     private void registerForSignalStrengthChanged() {
6290         for (Phone phone : PhoneFactory.getPhones()) {
6291             phone.getSignalStrengthController().registerForSignalStrengthChanged(this,
6292                     EVENT_SIGNAL_STRENGTH_CHANGED, phone.getPhoneId());
6293         }
6294     }
6295 
handleEventServiceStateChanged()6296     private void handleEventServiceStateChanged() {
6297         evaluateCarrierRoamingNtnEligibilityChange();
6298         handleServiceStateForSatelliteConnectionViaCarrier();
6299     }
6300 
handleServiceStateForSatelliteConnectionViaCarrier()6301     private void handleServiceStateForSatelliteConnectionViaCarrier() {
6302         for (Phone phone : PhoneFactory.getPhones()) {
6303             int subId = phone.getSubId();
6304             ServiceState serviceState = phone.getServiceState();
6305             if (serviceState == null || subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
6306                 continue;
6307             }
6308 
6309             synchronized (mSatelliteConnectedLock) {
6310                 CarrierRoamingSatelliteSessionStats sessionStats =
6311                         mCarrierRoamingSatelliteSessionStatsMap.get(subId);
6312                 if (DEBUG) {
6313                     plogd("handleServiceStateForSatelliteConnectionViaCarrier : SubId = " + subId
6314                             + "  isUsingNonTerrestrialNetwork = "
6315                             + serviceState.isUsingNonTerrestrialNetwork());
6316                 }
6317                 if (serviceState.isUsingNonTerrestrialNetwork()) {
6318                     if (sessionStats != null) {
6319                         sessionStats.onSignalStrength(phone);
6320                         if (!mWasSatelliteConnectedViaCarrier.get(subId)) {
6321                             // Log satellite connection start
6322                             sessionStats.onConnectionStart(phone);
6323                         }
6324                     }
6325 
6326                     resetCarrierRoamingSatelliteModeParams(subId);
6327                     mWasSatelliteConnectedViaCarrier.put(subId, true);
6328 
6329                     for (NetworkRegistrationInfo nri
6330                             : serviceState.getNetworkRegistrationInfoList()) {
6331                         if (nri.isNonTerrestrialNetwork()) {
6332                             mSatModeCapabilitiesForCarrierRoaming.put(subId,
6333                                     nri.getAvailableServices());
6334                         }
6335                     }
6336                 } else {
6337                     Boolean connected = mWasSatelliteConnectedViaCarrier.get(subId);
6338                     if (getWwanIsInService(serviceState)
6339                             || serviceState.getState() == ServiceState.STATE_POWER_OFF) {
6340                         resetCarrierRoamingSatelliteModeParams(subId);
6341                     } else if (connected != null && connected) {
6342                         // The device just got disconnected from a satellite network
6343                         // and is not connected to any terrestrial network that  has coverage
6344                         mLastSatelliteDisconnectedTimesMillis.put(subId, getElapsedRealtime());
6345 
6346                         plogd("sendMessageDelayed subId:" + subId
6347                                 + " phoneId:" + phone.getPhoneId()
6348                                 + " time:" + getSatelliteConnectionHysteresisTimeMillis(subId));
6349                         sendMessageDelayed(obtainMessage(EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT,
6350                                         phone.getPhoneId()),
6351                                 getSatelliteConnectionHysteresisTimeMillis(subId));
6352 
6353                         if (sessionStats != null) {
6354                             // Log satellite connection end
6355                             sessionStats.onConnectionEnd();
6356                         }
6357                     }
6358                     mWasSatelliteConnectedViaCarrier.put(subId, false);
6359                 }
6360                 updateLastNotifiedNtnModeAndNotify(phone);
6361                 updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(phone);
6362             }
6363         }
6364         determineAutoConnectSystemNotification();
6365     }
6366 
updateLastNotifiedNtnModeAndNotify(@ullable Phone phone)6367     private void updateLastNotifiedNtnModeAndNotify(@Nullable Phone phone) {
6368         if (phone == null) {
6369             plogd("updateLastNotifiedNtnModeAndNotify: phone is null");
6370             return;
6371         }
6372 
6373         int subId = phone.getSubId();
6374         synchronized (mSatelliteConnectedLock) {
6375             boolean initialized = mInitialized.get(subId);
6376             boolean lastNotifiedNtnMode = mLastNotifiedNtnMode.get(subId);
6377             boolean currNtnMode = isInSatelliteModeForCarrierRoaming(phone);
6378             plogd("updateLastNotifiedNtnModeAndNotify: subId=" + subId
6379                     + " initialized=" + initialized
6380                     + " lastNotifiedNtnMode=" + lastNotifiedNtnMode
6381                     + " currNtnMode=" + currNtnMode);
6382             if (!initialized || lastNotifiedNtnMode != currNtnMode) {
6383                 if (!initialized) mInitialized.put(subId, true);
6384                 mLastNotifiedNtnMode.put(subId, currNtnMode);
6385                 phone.notifyCarrierRoamingNtnModeChanged(currNtnMode);
6386                 updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(phone);
6387                 logCarrierRoamingSatelliteSessionStats(phone, lastNotifiedNtnMode, currNtnMode);
6388                 if(mIsNotificationShowing && !currNtnMode) {
6389                     dismissSatelliteNotification();
6390                 }
6391             }
6392         }
6393     }
6394 
6395     /**
6396      * map data policy to support unknown case at metrics
6397      * @param dataPolicy data support mode for the service type
6398      * @return corresponding value from {@link SatelliteConstants.SatelliteEntitlementServicePolicy}
6399      *
6400      */
6401     @SatelliteConstants.SatelliteEntitlementServicePolicy
mapDataPolicyForMetrics(int dataPolicy)6402     public int mapDataPolicyForMetrics(int dataPolicy) {
6403         switch (dataPolicy) {
6404             case CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED -> {
6405                 return SatelliteConstants.SATELLITE_ENTITLEMENT_SERVICE_POLICY_RESTRICTED;
6406             }
6407             case CarrierConfigManager.SATELLITE_DATA_SUPPORT_BANDWIDTH_CONSTRAINED -> {
6408                 return SatelliteConstants.SATELLITE_ENTITLEMENT_SERVICE_POLICY_CONSTRAINED;
6409             }
6410             case CarrierConfigManager.SATELLITE_DATA_SUPPORT_ALL -> {
6411                 return SatelliteConstants.SATELLITE_ENTITLEMENT_SERVICE_POLICY_UNCONSTRAINED;
6412             }
6413         }
6414         return SatelliteConstants.SATELLITE_ENTITLEMENT_SERVICE_POLICY_UNKNOWN;
6415     }
6416 
getSupportedSatelliteServicesOnSessionStart(List<Integer> supportedServices)6417     private int[] getSupportedSatelliteServicesOnSessionStart(List<Integer> supportedServices) {
6418         if (supportedServices == null || supportedServices.isEmpty()) {
6419             return new int[0];
6420         }
6421 
6422         return supportedServices.stream().mapToInt(Integer::intValue).toArray();
6423     }
6424 
logCarrierRoamingSatelliteSessionStats(@onNull Phone phone, boolean lastNotifiedNtnMode, boolean currNtnMode)6425     private void logCarrierRoamingSatelliteSessionStats(@NonNull Phone phone,
6426             boolean lastNotifiedNtnMode, boolean currNtnMode) {
6427         synchronized (mSatelliteConnectedLock) {
6428             int subId = phone.getSubId();
6429             if (!lastNotifiedNtnMode && currNtnMode) {
6430                 // Log satellite session start
6431                 CarrierRoamingSatelliteSessionStats sessionStats =
6432                         CarrierRoamingSatelliteSessionStats.getInstance(subId);
6433                 int[] supported_satellite_services =
6434                         getSupportedSatelliteServicesOnSessionStart(
6435                                 getSupportedSatelliteServicesForPlmn(subId,
6436                         phone.getServiceState().getOperatorNumeric()));
6437                 int dataPolicy = mapDataPolicyForMetrics(getSatelliteDataServicePolicyForPlmn(subId,
6438                         phone.getServiceState().getOperatorNumeric()));
6439 
6440                 sessionStats.onSessionStart(phone.getCarrierId(), phone,
6441                         supported_satellite_services, dataPolicy);
6442                 mCarrierRoamingSatelliteSessionStatsMap.put(subId, sessionStats);
6443                 mCarrierRoamingSatelliteControllerStats.onSessionStart(subId);
6444             } else if (lastNotifiedNtnMode && !currNtnMode) {
6445                 // Log satellite session end
6446                 CarrierRoamingSatelliteSessionStats sessionStats =
6447                         mCarrierRoamingSatelliteSessionStatsMap.get(subId);
6448                 sessionStats.onSessionEnd(subId);
6449                 mCarrierRoamingSatelliteSessionStatsMap.remove(subId);
6450                 mCarrierRoamingSatelliteControllerStats.onSessionEnd(subId);
6451             }
6452         }
6453     }
6454 
evaluateCarrierRoamingNtnEligibilityChange()6455     private void evaluateCarrierRoamingNtnEligibilityChange() {
6456         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
6457             plogd("evaluateCarrierRoamingNtnEligibilityChange: "
6458                     + "carrierRoamingNbIotNtn flag is disabled");
6459             return;
6460         }
6461 
6462         registerForSatelliteCommunicationAccessStateChanged();
6463 
6464         if (isSatelliteEnabledOrBeingEnabled()) {
6465             plogd("evaluateCarrierRoamingNtnEligibilityChange: "
6466                     + "Skip eligibility check as satellite is enabled or being enabled");
6467             return;
6468         }
6469 
6470         boolean eligible = isCarrierRoamingNtnEligible(getSatellitePhone());
6471         plogd("evaluateCarrierRoamingNtnEligibilityChange: "
6472                 + "isCarrierRoamingNtnEligible=" + eligible);
6473 
6474         if (eligible) {
6475             if (shouldStartNtnEligibilityHysteresisTimer(eligible)) {
6476                 startNtnEligibilityHysteresisTimer();
6477             }
6478         } else {
6479             stopNtnEligibilityHysteresisTimer();
6480             updateLastNotifiedNtnEligibilityAndNotify(false);
6481         }
6482     }
6483 
shouldStartNtnEligibilityHysteresisTimer(boolean eligible)6484     private boolean shouldStartNtnEligibilityHysteresisTimer(boolean eligible) {
6485         if (!eligible) {
6486             return false;
6487         }
6488 
6489         if (hasMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT)) {
6490             plogd("shouldStartNtnEligibilityHysteresisTimer: Timer is already running.");
6491             return false;
6492         }
6493 
6494         synchronized (mSatellitePhoneLock) {
6495             if (mLastNotifiedNtnEligibility != null && mLastNotifiedNtnEligibility) {
6496                 return false;
6497             }
6498         }
6499 
6500         return true;
6501     }
6502 
startNtnEligibilityHysteresisTimer()6503     private void startNtnEligibilityHysteresisTimer() {
6504         Phone satellitePhone = getSatellitePhone();
6505         if (satellitePhone == null) {
6506             ploge("startNtnEligibilityHysteresisTimer: mSatellitePhone is null.");
6507             return;
6508         }
6509 
6510         int subId = getSelectedSatelliteSubId();
6511         long timeout = getCarrierSupportedSatelliteNotificationHysteresisTimeMillis(subId);
6512         plogd("startNtnEligibilityHysteresisTimer: sendMessageDelayed subId=" + subId
6513                     + ", phoneId=" + satellitePhone.getPhoneId() + ", timeout=" + timeout);
6514         sendMessageDelayed(obtainMessage(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT),
6515                 timeout);
6516 
6517     }
6518 
stopNtnEligibilityHysteresisTimer()6519     private void stopNtnEligibilityHysteresisTimer() {
6520         if (hasMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT)) {
6521             removeMessages(EVENT_NOTIFY_NTN_ELIGIBILITY_HYSTERESIS_TIMED_OUT);
6522         }
6523     }
6524 
updateLastNotifiedNtnEligibilityAndNotify(boolean currentNtnEligibility)6525     private void updateLastNotifiedNtnEligibilityAndNotify(boolean currentNtnEligibility) {
6526         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
6527             plogd("notifyNtnEligibility: carrierRoamingNbIotNtn flag is disabled");
6528             return;
6529         }
6530 
6531         Phone satellitePhone = getSatellitePhone();
6532         if (satellitePhone == null) {
6533             ploge("notifyNtnEligibility: mSatellitePhone is null");
6534             return;
6535         }
6536 
6537         if (mOverrideNtnEligibility != null) {
6538             satellitePhone.notifyCarrierRoamingNtnEligibleStateChanged(currentNtnEligibility);
6539             return;
6540         }
6541 
6542         int selectedSatelliteSubId = getSelectedSatelliteSubId();
6543         synchronized (mSatellitePhoneLock) {
6544             plogd("notifyNtnEligibility: phoneId=" + satellitePhone.getPhoneId()
6545                     + " currentNtnEligibility=" + currentNtnEligibility);
6546             if (mLastNotifiedNtnEligibility == null
6547                     || mLastNotifiedNtnEligibility != currentNtnEligibility) {
6548                 mLastNotifiedNtnEligibility = currentNtnEligibility;
6549                 satellitePhone.notifyCarrierRoamingNtnEligibleStateChanged(currentNtnEligibility);
6550                 updateSatelliteSystemNotification(selectedSatelliteSubId,
6551                         CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL,
6552                         currentNtnEligibility);
6553             }
6554         }
6555     }
6556 
6557     /** Return last notified ntn eligibility. */
getLastNotifiedNtnEligibility(@onNull Phone phone)6558     public boolean getLastNotifiedNtnEligibility(@NonNull Phone phone) {
6559         int selectedSatelliteSubId = getSelectedSatelliteSubId();
6560         int subId = phone.getSubId();
6561         if (subId != selectedSatelliteSubId) {
6562             plogd("getLastNotifiedNtnEligibility: subId=" + subId
6563                     +  " does not match selectedSatelliteSubId=" + selectedSatelliteSubId);
6564             return false;
6565         }
6566 
6567         synchronized (mSatellitePhoneLock) {
6568             plogd("getLastNotifiedNtnEligibility: return " + mLastNotifiedNtnEligibility);
6569             return mLastNotifiedNtnEligibility;
6570         }
6571     }
6572 
getSatelliteConnectionHysteresisTimeMillis(int subId)6573     private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
6574         PersistableBundle config = getPersistableBundle(subId);
6575         return (config.getInt(
6576                 KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
6577     }
6578 
getCarrierSupportedSatelliteNotificationHysteresisTimeMillis(int subId)6579     private long getCarrierSupportedSatelliteNotificationHysteresisTimeMillis(int subId) {
6580         PersistableBundle config = getPersistableBundle(subId);
6581         return (config.getInt(
6582                 KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT) * 1000L);
6583     }
6584 
persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned)6585     private void persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned) {
6586         synchronized (mDeviceProvisionLock) {
6587             plogd("persistOemEnabledSatelliteProvisionStatus: isProvisioned=" + isProvisioned);
6588             if (mFeatureFlags.carrierRoamingNbIotNtn()) {
6589                 int subId = getNtnOnlySubscriptionId();
6590                 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
6591                     try {
6592                         mSubscriptionManagerService.setIsSatelliteProvisionedForNonIpDatagram(subId,
6593                                 isProvisioned);
6594                         plogd("persistOemEnabledSatelliteProvisionStatus: subId=" + subId);
6595                     } catch (IllegalArgumentException | SecurityException ex) {
6596                         ploge("setIsSatelliteProvisionedForNonIpDatagram: subId=" + subId + ", ex="
6597                                 + ex);
6598                     }
6599                 } else {
6600                     plogd("persistOemEnabledSatelliteProvisionStatus: INVALID_SUBSCRIPTION_ID");
6601                 }
6602             } else {
6603                 if (!loadSatelliteSharedPreferences()) return;
6604 
6605                 if (mSharedPreferences == null) {
6606                     ploge("persistOemEnabledSatelliteProvisionStatus: mSharedPreferences is null");
6607                 } else {
6608                     mSharedPreferences.edit().putBoolean(
6609                             OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY, isProvisioned).apply();
6610                 }
6611             }
6612         }
6613     }
6614 
6615     @Nullable
getPersistedDeviceProvisionStatus()6616     private boolean getPersistedDeviceProvisionStatus() {
6617         plogd("getPersistedDeviceProvisionStatus");
6618         synchronized (mDeviceProvisionLock) {
6619             if (mFeatureFlags.carrierRoamingNbIotNtn()) {
6620                 int subId = getNtnOnlySubscriptionId();
6621                 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
6622                     if (mSubscriptionManagerService.isSatelliteProvisionedForNonIpDatagram(subId)) {
6623                         return true;
6624                     }
6625                 }
6626 
6627                 List<SubscriptionInfo> activeSubscriptionInfoList =
6628                         mSubscriptionManagerService.getActiveSubscriptionInfoList(
6629                             mContext.getOpPackageName(), mContext.getAttributionTag(), true);
6630                 for (SubscriptionInfo info : activeSubscriptionInfoList) {
6631                     if (info.isSatelliteESOSSupported()) {
6632                         if (mSubscriptionManagerService.isSatelliteProvisionedForNonIpDatagram(
6633                                 info.getSubscriptionId())) {
6634                             Pair<String, Integer> subscriberIdPair = getSubscriberIdAndType(
6635                                     mSubscriptionManagerService.getSubscriptionInfo(subId));
6636                             String subscriberId = subscriberIdPair.first;
6637                             synchronized (mSatelliteTokenProvisionedLock) {
6638                                 mProvisionedSubscriberId.put(subscriberId, true);
6639                             }
6640                             return true;
6641                         }
6642                     }
6643                 }
6644                 return false;
6645             } else {
6646                 if (!loadSatelliteSharedPreferences()) return false;
6647 
6648                 if (mSharedPreferences == null) {
6649                     ploge("getPersistedDeviceProvisionStatus: mSharedPreferences is "
6650                             + "null");
6651                     return false;
6652                 } else {
6653                     return mSharedPreferences.getBoolean(
6654                             OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY, false);
6655                 }
6656             }
6657         }
6658     }
6659 
loadSatelliteSharedPreferences()6660     private boolean loadSatelliteSharedPreferences() {
6661         if (mSharedPreferences == null) {
6662             try {
6663                 mSharedPreferences =
6664                         mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
6665                                 Context.MODE_PRIVATE);
6666             } catch (Exception e) {
6667                 ploge("loadSatelliteSharedPreferences: Cannot get default "
6668                         + "shared preferences, e=" + e);
6669                 return false;
6670             }
6671         }
6672         return true;
6673     }
6674 
handleIsSatelliteProvisionedDoneEvent(@onNull AsyncResult ar)6675     private void handleIsSatelliteProvisionedDoneEvent(@NonNull AsyncResult ar) {
6676         logd("handleIsSatelliteProvisionedDoneEvent:");
6677         SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj;
6678 
6679         Bundle bundle = new Bundle();
6680         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED,
6681                 Boolean.TRUE.equals(isDeviceProvisioned()));
6682         ((ResultReceiver) request.argument).send(SATELLITE_RESULT_SUCCESS, bundle);
6683         decrementResultReceiverCount("SC:requestIsSatelliteProvisioned");
6684     }
6685 
getWaitForSatelliteEnablingResponseTimeoutMillis()6686     private long getWaitForSatelliteEnablingResponseTimeoutMillis() {
6687         return mContext.getResources().getInteger(
6688                 R.integer.config_wait_for_satellite_enabling_response_timeout_millis);
6689     }
6690 
getWaitForCellularModemOffTimeoutMillis()6691     private long getWaitForCellularModemOffTimeoutMillis() {
6692         return mContext.getResources().getInteger(
6693                 R.integer.config_satellite_wait_for_cellular_modem_off_timeout_millis);
6694     }
6695 
startWaitForCellularModemOffTimer()6696     private void startWaitForCellularModemOffTimer() {
6697         synchronized (mIsRadioOnLock) {
6698             if (hasMessages(EVENT_WAIT_FOR_CELLULAR_MODEM_OFF_TIMED_OUT)) {
6699                 plogd("startWaitForCellularModemOffTimer: the timer was already started");
6700                 return;
6701             }
6702             long timeoutMillis = getWaitForCellularModemOffTimeoutMillis();
6703             plogd("Start timer to wait for cellular modem OFF state, timeoutMillis="
6704                     + timeoutMillis);
6705             sendMessageDelayed(obtainMessage(EVENT_WAIT_FOR_CELLULAR_MODEM_OFF_TIMED_OUT),
6706                     timeoutMillis);
6707         }
6708     }
6709 
stopWaitForCellularModemOffTimer()6710     private void stopWaitForCellularModemOffTimer() {
6711         synchronized (mSatelliteEnabledRequestLock) {
6712             plogd("Stop timer to wait for cellular modem OFF state");
6713             removeMessages(EVENT_WAIT_FOR_CELLULAR_MODEM_OFF_TIMED_OUT);
6714         }
6715     }
6716 
startWaitForSatelliteEnablingResponseTimer( @onNull RequestSatelliteEnabledArgument argument)6717     private void startWaitForSatelliteEnablingResponseTimer(
6718             @NonNull RequestSatelliteEnabledArgument argument) {
6719         synchronized (mSatelliteEnabledRequestLock) {
6720             if (hasMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument)) {
6721                 plogd("WaitForSatelliteEnablingResponseTimer of request ID "
6722                         + argument.requestId + " was already started");
6723                 return;
6724             }
6725             plogd("Start timer to wait for response of the satellite enabling request ID="
6726                     + argument.requestId + ", enableSatellite=" + argument.enableSatellite
6727                     + ", mWaitTimeForSatelliteEnablingResponse="
6728                     + mWaitTimeForSatelliteEnablingResponse);
6729             sendMessageDelayed(obtainMessage(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT,
6730                             argument), mWaitTimeForSatelliteEnablingResponse);
6731         }
6732     }
6733 
stopWaitForSatelliteEnablingResponseTimer( @onNull RequestSatelliteEnabledArgument argument)6734     private void stopWaitForSatelliteEnablingResponseTimer(
6735             @NonNull RequestSatelliteEnabledArgument argument) {
6736         synchronized (mSatelliteEnabledRequestLock) {
6737             plogd("Stop timer to wait for response of the satellite enabling request ID="
6738                     + argument.requestId + ", enableSatellite=" + argument.enableSatellite);
6739             removeMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument);
6740         }
6741     }
6742 
shouldProcessEventSetSatelliteEnabledDone( @onNull RequestSatelliteEnabledArgument argument)6743     private boolean shouldProcessEventSetSatelliteEnabledDone(
6744             @NonNull RequestSatelliteEnabledArgument argument) {
6745         synchronized (mSatelliteEnabledRequestLock) {
6746             if (hasMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument)) {
6747                 return true;
6748             }
6749             return false;
6750         }
6751     }
6752 
startWaitForUpdateSystemSelectionChannelsResponseTimer( @onNull UpdateSystemSelectionChannelsArgument argument)6753     private void startWaitForUpdateSystemSelectionChannelsResponseTimer(
6754             @NonNull UpdateSystemSelectionChannelsArgument argument) {
6755         synchronized (mSatelliteEnabledRequestLock) {
6756             if (hasMessages(
6757                     EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT, argument)) {
6758                 plogd("WaitForUpdateSystemSelectionChannelsResponseTimer of request ID "
6759                         + argument.requestId + " was already started");
6760                 return;
6761             }
6762             plogd("Start timer to wait for response of the system selection channels update request"
6763                     + " ID=" + argument.requestId + ", mWaitTimeForSatelliteEnablingResponse="
6764                     + mWaitTimeForSatelliteEnablingResponse);
6765             sendMessageDelayed(
6766                 obtainMessage(EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT,
6767                     argument), mWaitTimeForSatelliteEnablingResponse);
6768         }
6769     }
6770 
stopWaitForUpdateSystemSelectionChannelsResponseTimer( @onNull UpdateSystemSelectionChannelsArgument argument)6771     private void stopWaitForUpdateSystemSelectionChannelsResponseTimer(
6772             @NonNull UpdateSystemSelectionChannelsArgument argument) {
6773         synchronized (mSatelliteEnabledRequestLock) {
6774             plogd("Stop timer to wait for response of the system selection channels"
6775                       + " update request ID=" + argument.requestId);
6776             removeMessages(
6777                 EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT, argument);
6778         }
6779     }
6780 
shouldProcessEventUpdateSystemSelectionChannelsDone( @onNull UpdateSystemSelectionChannelsArgument argument)6781     private boolean shouldProcessEventUpdateSystemSelectionChannelsDone(
6782             @NonNull UpdateSystemSelectionChannelsArgument argument) {
6783         synchronized (mSatelliteEnabledRequestLock) {
6784             if (hasMessages(
6785                     EVENT_WAIT_FOR_UPDATE_SYSTEM_SELECTION_CHANNELS_RESPONSE_TIMED_OUT, argument)) {
6786                 return true;
6787             }
6788             return false;
6789         }
6790     }
6791 
startWaitForUpdateSatelliteEnableAttributesResponseTimer( @onNull RequestSatelliteEnabledArgument argument)6792     private void startWaitForUpdateSatelliteEnableAttributesResponseTimer(
6793             @NonNull RequestSatelliteEnabledArgument argument) {
6794         synchronized (mSatelliteEnabledRequestLock) {
6795             if (hasMessages(EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT,
6796                     argument)) {
6797                 plogd("WaitForUpdateSatelliteEnableAttributesResponseTimer of request ID "
6798                         + argument.requestId + " was already started");
6799                 return;
6800             }
6801             plogd("Start timer to wait for response of the update satellite enable attributes"
6802                     + " request ID=" + argument.requestId
6803                     + ", enableSatellite=" + argument.enableSatellite
6804                     + ", mWaitTimeForSatelliteEnablingResponse="
6805                     + mWaitTimeForSatelliteEnablingResponse);
6806             sendMessageDelayed(obtainMessage(
6807                     EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT,
6808                     argument), mWaitTimeForSatelliteEnablingResponse);
6809         }
6810     }
6811 
stopWaitForUpdateSatelliteEnableAttributesResponseTimer( @onNull RequestSatelliteEnabledArgument argument)6812     private void stopWaitForUpdateSatelliteEnableAttributesResponseTimer(
6813             @NonNull RequestSatelliteEnabledArgument argument) {
6814         synchronized (mSatelliteEnabledRequestLock) {
6815             plogd("Stop timer to wait for response of the enable attributes update request ID="
6816                     + argument.requestId + ", enableSatellite=" + argument.enableSatellite);
6817             removeMessages(
6818                     EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT, argument);
6819         }
6820     }
6821 
shouldProcessEventUpdateSatelliteEnableAttributesDone( @onNull RequestSatelliteEnabledArgument argument)6822     private boolean shouldProcessEventUpdateSatelliteEnableAttributesDone(
6823             @NonNull RequestSatelliteEnabledArgument argument) {
6824         synchronized (mSatelliteEnabledRequestLock) {
6825             if (hasMessages(EVENT_WAIT_FOR_UPDATE_SATELLITE_ENABLE_ATTRIBUTES_RESPONSE_TIMED_OUT,
6826                     argument)) {
6827                 return true;
6828             }
6829             return false;
6830         }
6831     }
6832 
handleEventWaitForSatelliteEnablingResponseTimedOut( @onNull RequestSatelliteEnabledArgument argument)6833     private void handleEventWaitForSatelliteEnablingResponseTimedOut(
6834             @NonNull RequestSatelliteEnabledArgument argument) {
6835         plogw("Timed out to wait for response of the satellite enabling request ID="
6836                 + argument.requestId + ", enableSatellite=" + argument.enableSatellite);
6837 
6838         argument.callback.accept(SATELLITE_RESULT_MODEM_TIMEOUT);
6839         if (argument.enableSatellite) {
6840             resetSatelliteEnabledRequest();
6841             abortSatelliteEnableAttributesUpdateRequest(SATELLITE_RESULT_REQUEST_ABORTED);
6842             if (getSatelliteDisabledRequest() == null) {
6843                 IIntegerConsumer callback = new IIntegerConsumer.Stub() {
6844                     @Override
6845                     public void accept(int result) {
6846                         plogd("handleEventWaitForSatelliteEnablingResponseTimedOut: "
6847                                 + "disable satellite result=" + result);
6848                     }
6849                 };
6850                 Consumer<Integer> result =
6851                         FunctionalUtils.ignoreRemoteException(callback::accept);
6852 
6853                 RequestSatelliteEnabledArgument request;
6854                 synchronized (mSatelliteEnabledRequestLock) {
6855                     mSatelliteDisabledRequest = new RequestSatelliteEnabledArgument(
6856                             false, false, false, result);
6857                     request = mSatelliteDisabledRequest;
6858                 }
6859 
6860                 sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
6861             }
6862 
6863             mControllerMetricsStats.reportServiceEnablementFailCount();
6864             mSessionMetricsStats.setInitializationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
6865                     .setSatelliteTechnology(getSupportedNtnRadioTechnology())
6866                     .setInitializationProcessingTime(
6867                             getElapsedRealtime() - mSessionProcessingTimeStamp)
6868                     .setIsDemoMode(mIsDemoModeEnabled)
6869                     .setCarrierId(getSatelliteCarrierId())
6870                     .reportSessionMetrics();
6871         } else {
6872             resetSatelliteDisabledRequest();
6873             mControllerMetricsStats.onSatelliteDisabled();
6874             mSessionMetricsStats.setTerminationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
6875                     .setSatelliteTechnology(getSupportedNtnRadioTechnology())
6876                     .setTerminationProcessingTime(
6877                             getElapsedRealtime() - mSessionProcessingTimeStamp)
6878                     .setSessionDurationSec(calculateSessionDurationTimeSec())
6879                     .reportSessionMetrics();
6880         }
6881         notifyEnablementFailedToSatelliteSessionController(argument.enableSatellite);
6882         mSessionStartTimeStamp = 0;
6883         mSessionProcessingTimeStamp = 0;
6884     }
6885 
handleCmdUpdateNtnSignalStrengthReporting(boolean shouldReport)6886     private void handleCmdUpdateNtnSignalStrengthReporting(boolean shouldReport) {
6887         if (!isSatelliteEnabledOrBeingEnabled()) {
6888             plogd("handleCmdUpdateNtnSignalStrengthReporting: ignore request, satellite is "
6889                     + "disabled");
6890             return;
6891         }
6892 
6893         mLatestRequestedStateForNtnSignalStrengthReport.set(shouldReport);
6894         if (mIsModemEnabledReportingNtnSignalStrength.get() == shouldReport) {
6895             plogd("handleCmdUpdateNtnSignalStrengthReporting: ignore request. "
6896                     + "mIsModemEnabledReportingNtnSignalStrength="
6897                     + mIsModemEnabledReportingNtnSignalStrength.get());
6898             return;
6899         }
6900 
6901         updateNtnSignalStrengthReporting(shouldReport);
6902     }
6903 
updateNtnSignalStrengthReporting(boolean shouldReport)6904     private void updateNtnSignalStrengthReporting(boolean shouldReport) {
6905         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
6906                 shouldReport, SatelliteServiceUtils.getPhone());
6907         Message onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE,
6908                 request);
6909         if (shouldReport) {
6910             plogd("updateNtnSignalStrengthReporting: startSendingNtnSignalStrength");
6911             mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
6912         } else {
6913             plogd("updateNtnSignalStrengthReporting: stopSendingNtnSignalStrength");
6914             mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted);
6915         }
6916     }
6917 
6918     /**
6919      * This API can be used by only CTS to override the cached value for the device overlay config
6920      * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
6921      * outgoing satellite datagrams should be sent to modem in demo mode.
6922      *
6923      * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
6924      * satellite modem or not.
6925      *
6926      * @return {@code true} if the operation is successful, {@code false} otherwise.
6927      */
setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode)6928     public boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) {
6929         if (!isMockModemAllowed()) {
6930             plogd("setShouldSendDatagramToModemInDemoMode: mock modem not allowed.");
6931             return false;
6932         }
6933 
6934         mDatagramController.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
6935         return true;
6936     }
6937 
determineAutoConnectSystemNotification()6938     private void determineAutoConnectSystemNotification() {
6939         Pair<Boolean, Integer> isNtn = isUsingNonTerrestrialNetworkViaCarrier();
6940         boolean suppressSatelliteNotification = mSharedPreferences.getBoolean(
6941                 SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false);
6942         if (suppressSatelliteNotification) {
6943             // System already displayed the notification and user interacted with it.
6944             // System will show notification again after 30 days.
6945             long lastSetTimestamp = mSharedPreferences.getLong(
6946                     SATELLITE_SYSTEM_NOTIFICATION_TIME, 0L);
6947             logv("determineAutoConnectSystemNotification lastSetTimestamp = " + lastSetTimestamp);
6948             long currentTime = System.currentTimeMillis();
6949             int subId = getSelectedSatelliteSubId();
6950             long throttleTime = getNotificationDisplayThrottleTimeout(subId);
6951             if (lastSetTimestamp == 0L || currentTime - lastSetTimestamp >= throttleTime) {
6952                 // Reset the flag and update the timestamp
6953                 logd("determineAutoConnectSystemNotification: reset preference data");
6954                 suppressSatelliteNotification = false;
6955                 mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY,
6956                         false).remove(SATELLITE_SYSTEM_NOTIFICATION_TIME).apply();
6957             }
6958         }
6959         if (DEBUG) {
6960             logd("determineAutoConnectSystemNotification: isNtn.first = " + isNtn.first
6961                     + " IsNotiToShow = " + !suppressSatelliteNotification
6962                     + " mIsNotificationShowing = " + mIsNotificationShowing);
6963         }
6964         if (isNtn.first) {
6965             if (!suppressSatelliteNotification && getCarrierRoamingNtnConnectType(isNtn.second)
6966                     == CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC) {
6967                 updateSatelliteSystemNotification(isNtn.second,
6968                         CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC,
6969                         /*visible*/ true);
6970             }
6971         } else if (mIsNotificationShowing
6972                 && !isSatelliteConnectedViaCarrierWithinHysteresisTime().first) {
6973             // Dismiss the notification if it is still displaying.
6974             dismissSatelliteNotification();
6975         }
6976     }
6977 
dismissSatelliteNotification()6978     private void dismissSatelliteNotification() {
6979         mIsNotificationShowing = false;
6980         updateSatelliteSystemNotification(-1, -1,/*visible*/ false);
6981     }
6982 
isSatelliteSystemNotificationsEnabled(int carrierRoamingNtnConnectType)6983     public boolean isSatelliteSystemNotificationsEnabled(int carrierRoamingNtnConnectType) {
6984         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
6985             return false;
6986         }
6987         if (carrierRoamingNtnConnectType
6988             != CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
6989             return true;
6990         }
6991         boolean notifySatelliteAvailabilityEnabled =
6992             mContext.getResources().getBoolean(R.bool.config_satellite_should_notify_availability);
6993         Boolean isSatelliteSupported = getIsSatelliteSupported();
6994         if(isSatelliteSupported == null) {
6995             return false;
6996         }
6997         int subId = getSelectedSatelliteSubId();
6998         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
6999         logd("isSatelliteSystemNotificationsEnabled: SatelliteSubId = " + subId);
7000         return notifySatelliteAvailabilityEnabled
7001                 && isSatelliteSupported
7002                 && isValidSubscriptionId(subId)
7003                 && ((isSatelliteSupportedViaCarrier(subId)
7004                 && (getCarrierRoamingNtnConnectType(subId)
7005                 == CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL))
7006                 || subInfo.isOnlyNonTerrestrialNetwork());
7007     }
7008 
isDataServiceSupported(int subId)7009     private boolean isDataServiceSupported(int subId) {
7010         int[] services = getSupportedServicesOnCarrierRoamingNtn(subId);
7011         return ArrayUtils.contains(services, NetworkRegistrationInfo.SERVICE_TYPE_DATA);
7012     }
7013 
7014     /**
7015      * Update the system notification to reflect the current satellite status, that's either already
7016      * connected OR needs to be manually enabled. The device should only display one notification
7017      * at a time to prevent confusing the user, so the same NOTIFICATION_CHANNEL and NOTIFICATION_ID
7018      * are used.
7019      *
7020      * @param subId The subId that provides the satellite connection.
7021      * @param carrierRoamingNtnConnectType {@link CarrierConfigManager
7022      * .CARRIER_ROAMING_NTN_CONNECT_TYPE}
7023      * @param visible {@code true} to show the notification, {@code false} to cancel it.
7024      */
updateSatelliteSystemNotification(int subId, @CARRIER_ROAMING_NTN_CONNECT_TYPE int carrierRoamingNtnConnectType, boolean visible)7025     private void updateSatelliteSystemNotification(int subId,
7026             @CARRIER_ROAMING_NTN_CONNECT_TYPE int carrierRoamingNtnConnectType, boolean visible) {
7027         if (!isSatelliteSystemNotificationsEnabled(carrierRoamingNtnConnectType)) {
7028             plogd("updateSatelliteSystemNotification: satellite notifications are not enabled.");
7029             return;
7030         }
7031 
7032         plogd("updateSatelliteSystemNotification subId=" + subId + ", carrierRoamingNtnConnectType="
7033                 + SatelliteServiceUtils.carrierRoamingNtnConnectTypeToString(
7034                 carrierRoamingNtnConnectType) + ", visible=" + visible);
7035         final NotificationChannel notificationChannel = new NotificationChannel(
7036                 NOTIFICATION_CHANNEL_ID,
7037                 NOTIFICATION_CHANNEL,
7038                 NotificationManager.IMPORTANCE_DEFAULT);
7039         notificationChannel.setSound(null, null);
7040         NotificationManager notificationManager = mContext.getSystemService(
7041                 NotificationManager.class);
7042         if (notificationManager == null) {
7043             ploge("updateSatelliteSystemNotification: notificationManager is null");
7044             return;
7045         }
7046         if (!visible) { // Cancel if any.
7047             notificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID, UserHandle.ALL);
7048             return;
7049         }
7050         notificationManager.createNotificationChannel(notificationChannel);
7051 
7052         int title = R.string.satellite_notification_title;
7053         int summary = R.string.satellite_notification_summary;
7054         if (carrierRoamingNtnConnectType
7055                 == CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
7056             title = R.string.satellite_notification_manual_title;
7057             summary = R.string.satellite_notification_manual_summary;
7058         } else if (carrierRoamingNtnConnectType
7059                 == CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC
7060                 && isDataServiceSupported(subId)) {
7061             // In Auto Connected mode, if data services supported, show data supported summary
7062             summary = R.string.satellite_notification_summary_with_data;
7063         }
7064 
7065         Notification.Builder notificationBuilder = new Notification.Builder(mContext,
7066                 NOTIFICATION_CHANNEL_ID)
7067                 .setContentTitle(mContext.getResources().getString(title))
7068                 .setContentText(mContext.getResources().getString(summary))
7069                 .setSmallIcon(R.drawable.ic_android_satellite_24px)
7070                 .setAutoCancel(true)
7071                 .setColor(mContext.getColor(
7072                         com.android.internal.R.color.system_notification_accent_color))
7073                 .setVisibility(Notification.VISIBILITY_PUBLIC);
7074 
7075         // Intent for `Open Messages` [Button 1]
7076         Intent openMessageIntent = new Intent();
7077         openMessageIntent.setAction(OPEN_MESSAGE_BUTTON);
7078         PendingIntent openMessagePendingIntent = PendingIntent.getBroadcast(mContext, 0,
7079                 openMessageIntent, PendingIntent.FLAG_IMMUTABLE);
7080         Notification.Action actionOpenMessage = new Notification.Action.Builder(0,
7081                 mContext.getResources().getString(R.string.satellite_notification_open_message),
7082                 openMessagePendingIntent).build();
7083         notificationBuilder.addAction(actionOpenMessage);   // Handle `Open Messages` button
7084 
7085         // Button for `How it works` [Button 2]
7086         Intent howItWorksIntent = new Intent();
7087         howItWorksIntent.setAction(HOW_IT_WORKS_BUTTON);
7088         howItWorksIntent.putExtra("SUBID", subId);
7089         PendingIntent howItWorksPendingIntent = PendingIntent.getBroadcast(mContext, 0,
7090                 howItWorksIntent, PendingIntent.FLAG_IMMUTABLE);
7091         Notification.Action actionHowItWorks = new Notification.Action.Builder(0,
7092                 mContext.getResources().getString(R.string.satellite_notification_how_it_works),
7093                 howItWorksPendingIntent).build();
7094         notificationBuilder.addAction(actionHowItWorks);    // Handle `How it works` button
7095 
7096         // Intent for clicking the main notification body
7097         Intent notificationClickIntent = new Intent(ACTION_NOTIFICATION_CLICK);
7098         PendingIntent notificationClickPendingIntent = PendingIntent.getBroadcast(mContext, 0,
7099                 notificationClickIntent, PendingIntent.FLAG_IMMUTABLE);
7100         notificationBuilder.setContentIntent(
7101                 notificationClickPendingIntent); // Handle notification body click
7102 
7103         // Intent for dismissing/swiping the notification
7104         Intent deleteIntent = new Intent(ACTION_NOTIFICATION_DISMISS);
7105         PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext, 0, deleteIntent,
7106                 PendingIntent.FLAG_IMMUTABLE);
7107         notificationBuilder.setDeleteIntent(
7108                 deletePendingIntent);  // Handle notification swipe/dismiss
7109 
7110         notificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
7111                 notificationBuilder.build(), UserHandle.ALL);
7112 
7113         // The Intent filter is to receive the above four events.
7114         IntentFilter filter = new IntentFilter();
7115         filter.addAction(OPEN_MESSAGE_BUTTON);
7116         filter.addAction(HOW_IT_WORKS_BUTTON);
7117         filter.addAction(ACTION_NOTIFICATION_CLICK);
7118         filter.addAction(ACTION_NOTIFICATION_DISMISS);
7119         mContext.registerReceiver(mNotificationInteractionBroadcastReceiver, filter,
7120                 Context.RECEIVER_EXPORTED);
7121 
7122         mIsNotificationShowing = true;
7123         mCarrierRoamingSatelliteControllerStats.reportCountOfSatelliteNotificationDisplayed(subId);
7124         mCarrierRoamingSatelliteControllerStats.reportCarrierId(getSatelliteCarrierId());
7125         mSessionMetricsStats.addCountOfSatelliteNotificationDisplayed();
7126     }
7127 
7128     private final BroadcastReceiver mNotificationInteractionBroadcastReceiver =
7129             new BroadcastReceiver() {
7130                 @Override
7131                 public void onReceive(Context context, Intent receivedIntent) {
7132                     String intentAction = receivedIntent.getAction();
7133                     if (TextUtils.isEmpty(intentAction)) {
7134                         loge("Received empty action from the notification");
7135                         return;
7136                     }
7137                     if (DBG) {
7138                         plogd("Notification Broadcast recvd action = "
7139                                 + receivedIntent.getAction());
7140                     }
7141                     boolean closeStatusBar = true;
7142                     switch (intentAction) {
7143                         case OPEN_MESSAGE_BUTTON -> {
7144                             // Add action to invoke message application.
7145                             // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
7146                             Optional<Intent> nullableIntent = Optional.ofNullable(
7147                                     Telephony.Sms.getDefaultSmsPackage(context)).flatMap(
7148                                     packageName -> {
7149                                         PackageManager pm = context.getPackageManager();
7150                                         return Optional.ofNullable(
7151                                                 pm.getLaunchIntentForPackage(packageName));
7152                                     });
7153                             // If nullableIntent is null, create new Intent for most common way to
7154                             // invoke
7155                             // message app.
7156                             Intent finalIntent = nullableIntent.map(intent -> {
7157                                 // Invoke the home screen of default message application.
7158                                 intent.setAction(Intent.ACTION_MAIN);
7159                                 intent.addCategory(Intent.CATEGORY_HOME);
7160                                 return intent;
7161                             }).orElseGet(() -> {
7162                                 ploge("showSatelliteSystemNotification: no default sms package "
7163                                         + "name, Invoke default sms compose window instead");
7164                                 Intent newIntent = new Intent(Intent.ACTION_VIEW);
7165                                 newIntent.setData(Uri.parse("sms:"));
7166                                 return newIntent;
7167                             });
7168                             context.startActivity(finalIntent);
7169                         }
7170                         case HOW_IT_WORKS_BUTTON -> {
7171                             int subId = receivedIntent.getIntExtra("SUBID", -1);
7172                             Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
7173                             intentSatelliteSetting.putExtra("sub_id", subId);
7174                             intentSatelliteSetting.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
7175                             context.startActivity(intentSatelliteSetting);
7176 
7177                         }
7178                         case ACTION_NOTIFICATION_DISMISS -> closeStatusBar = false;
7179                     }
7180                     // Note : ACTION_NOTIFICATION_DISMISS is not required to handled
7181                     dismissNotificationAndUpdatePref(closeStatusBar);
7182                 }
7183             };
7184 
dismissNotificationAndUpdatePref(boolean closeStatusBar)7185     private void dismissNotificationAndUpdatePref(boolean closeStatusBar) {
7186         dismissSatelliteNotification();
7187         if (closeStatusBar) {
7188             // Collapse the status bar once user interact with notification.
7189             StatusBarManager statusBarManager = mContext.getSystemService(StatusBarManager.class);
7190             if (statusBarManager != null) {
7191                 statusBarManager.collapsePanels();
7192             }
7193         }
7194         // update the sharedpref only when user interacted with the notification.
7195         mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, true).apply();
7196         mSharedPreferences.edit().putLong(SATELLITE_SYSTEM_NOTIFICATION_TIME,
7197                 System.currentTimeMillis()).apply();
7198         mContext.unregisterReceiver(mNotificationInteractionBroadcastReceiver);
7199     }
7200 
resetCarrierRoamingSatelliteModeParams()7201     private void resetCarrierRoamingSatelliteModeParams() {
7202         for (Phone phone : PhoneFactory.getPhones()) {
7203             resetCarrierRoamingSatelliteModeParams(phone.getSubId());
7204         }
7205     }
7206 
resetCarrierRoamingSatelliteModeParams(int subId)7207     private void resetCarrierRoamingSatelliteModeParams(int subId) {
7208         synchronized (mSatelliteConnectedLock) {
7209             mLastSatelliteDisconnectedTimesMillis.put(subId, null);
7210             mSatModeCapabilitiesForCarrierRoaming.remove(subId);
7211             mWasSatelliteConnectedViaCarrier.put(subId, false);
7212         }
7213     }
7214 
7215     /**
7216      * Read carrier config items for satellite
7217      *
7218      * @param subId Associated subscription ID
7219      * @return PersistableBundle including carrier config values
7220      */
7221     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
7222     @NonNull
getPersistableBundle(int subId)7223     public PersistableBundle getPersistableBundle(int subId) {
7224         synchronized (mCarrierConfigArrayLock) {
7225             PersistableBundle config = mCarrierConfigArray.get(subId);
7226             if (config == null) {
7227                 config = getConfigForSubId(subId);
7228                 mCarrierConfigArray.put(subId, config);
7229             }
7230             return config;
7231         }
7232     }
7233 
7234     // Should be invoked only when session termination done or session termination failed.
calculateSessionDurationTimeSec()7235     private int calculateSessionDurationTimeSec() {
7236         return (int) (
7237                 (getElapsedRealtime() - mSessionStartTimeStamp
7238                 - mSessionMetricsStats.getSessionInitializationProcessingTimeMillis()
7239                 - mSessionMetricsStats.getSessionTerminationProcessingTimeMillis()) / 1000);
7240     }
7241 
notifyEnablementFailedToSatelliteSessionController(boolean enabled)7242     private void notifyEnablementFailedToSatelliteSessionController(boolean enabled) {
7243         if (mSatelliteSessionController != null) {
7244             mSatelliteSessionController.onSatelliteEnablementFailed(enabled);
7245         } else {
7246             ploge("notifyEnablementFailedToSatelliteSessionController: mSatelliteSessionController"
7247                     + " is not initialized yet");
7248         }
7249     }
7250 
abortSatelliteEnableRequest(@atelliteManager.SatelliteResult int resultCode)7251     private void abortSatelliteEnableRequest(@SatelliteManager.SatelliteResult int resultCode) {
7252         synchronized (mSatelliteEnabledRequestLock) {
7253             if (mSatelliteEnabledRequest != null) {
7254                 plogw("abortSatelliteEnableRequest");
7255                 if (resultCode == SATELLITE_RESULT_SUCCESS) {
7256                     resultCode = SATELLITE_RESULT_REQUEST_ABORTED;
7257                 }
7258                 mSatelliteEnabledRequest.callback.accept(resultCode);
7259                 stopWaitForSatelliteEnablingResponseTimer(mSatelliteEnabledRequest);
7260                 mSatelliteEnabledRequest = null;
7261             }
7262         }
7263     }
7264 
abortSatelliteDisableRequest(@atelliteManager.SatelliteResult int resultCode)7265     private void abortSatelliteDisableRequest(@SatelliteManager.SatelliteResult int resultCode) {
7266         synchronized (mSatelliteEnabledRequestLock) {
7267             if (mSatelliteDisabledRequest != null) {
7268                 plogd("abortSatelliteDisableRequest");
7269                 mSatelliteDisabledRequest.callback.accept(resultCode);
7270                 stopWaitForSatelliteEnablingResponseTimer(mSatelliteDisabledRequest);
7271                 mSatelliteDisabledRequest = null;
7272             }
7273         }
7274     }
7275 
abortSatelliteEnableAttributesUpdateRequest( @atelliteManager.SatelliteResult int resultCode)7276     private void abortSatelliteEnableAttributesUpdateRequest(
7277             @SatelliteManager.SatelliteResult int resultCode) {
7278         synchronized (mSatelliteEnabledRequestLock) {
7279             if (mSatelliteEnableAttributesUpdateRequest != null) {
7280                 plogd("abortSatelliteEnableAttributesUpdateRequest");
7281                 if (resultCode == SATELLITE_RESULT_SUCCESS) {
7282                     resultCode = SATELLITE_RESULT_REQUEST_ABORTED;
7283                 }
7284                 mSatelliteEnableAttributesUpdateRequest.callback.accept(resultCode);
7285                 stopWaitForUpdateSatelliteEnableAttributesResponseTimer(
7286                         mSatelliteEnableAttributesUpdateRequest);
7287                 mSatelliteEnableAttributesUpdateRequest = null;
7288             }
7289         }
7290     }
7291 
stopWaitForEnableResponseTimers()7292     private void stopWaitForEnableResponseTimers() {
7293         plogd("stopWaitForEnableResponseTimers");
7294         removeMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT);
7295     }
7296 
getDemoPointingAlignedDurationMillisFromResources()7297     private long getDemoPointingAlignedDurationMillisFromResources() {
7298         long durationMillis = 15000L;
7299         try {
7300             durationMillis = mContext.getResources().getInteger(
7301                     R.integer.config_demo_pointing_aligned_duration_millis);
7302         } catch (Resources.NotFoundException ex) {
7303             loge("getPointingAlignedDurationMillis: ex=" + ex);
7304         }
7305 
7306         return durationMillis;
7307     }
7308 
7309     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDemoPointingAlignedDurationMillis()7310     public long getDemoPointingAlignedDurationMillis() {
7311         return mDemoPointingAlignedDurationMillis;
7312     }
7313 
getDemoPointingNotAlignedDurationMillisFromResources()7314     private long getDemoPointingNotAlignedDurationMillisFromResources() {
7315         long durationMillis = 30000L;
7316         try {
7317             durationMillis = mContext.getResources().getInteger(
7318                     R.integer.config_demo_pointing_not_aligned_duration_millis);
7319         } catch (Resources.NotFoundException ex) {
7320             loge("getPointingNotAlignedDurationMillis: ex=" + ex);
7321         }
7322 
7323         return durationMillis;
7324     }
7325 
7326     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDemoPointingNotAlignedDurationMillis()7327     public long getDemoPointingNotAlignedDurationMillis() {
7328         return mDemoPointingNotAlignedDurationMillis;
7329     }
7330 
7331     /** Returns {@code true} if WWAN is in service, else {@code false}.*/
7332     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getWwanIsInService(@onNull ServiceState serviceState)7333     public boolean getWwanIsInService(@NonNull ServiceState serviceState) {
7334         List<NetworkRegistrationInfo> nriList = serviceState
7335                 .getNetworkRegistrationInfoListForTransportType(
7336                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
7337 
7338         for (NetworkRegistrationInfo nri : nriList) {
7339             if (nri.isInService()) {
7340                 logv("getWwanIsInService: return true");
7341                 return true;
7342             }
7343         }
7344 
7345         logv("getWwanIsInService: return false");
7346         return false;
7347     }
7348 
logv(@onNull String log)7349     private static void logv(@NonNull String log) {
7350         Log.v(TAG, log);
7351     }
7352 
logd(@onNull String log)7353     private static void logd(@NonNull String log) {
7354         Log.d(TAG, log);
7355     }
7356 
logw(@onNull String log)7357     private static void logw(@NonNull String log) {
7358         Log.w(TAG, log);
7359     }
7360 
loge(@onNull String log)7361     private static void loge(@NonNull String log) {
7362         Log.e(TAG, log);
7363     }
7364 
plogd(@onNull String log)7365     private void plogd(@NonNull String log) {
7366         Log.d(TAG, log);
7367         if (mPersistentLogger != null) {
7368             mPersistentLogger.debug(TAG, log);
7369         }
7370     }
7371 
plogw(@onNull String log)7372     private void plogw(@NonNull String log) {
7373         Log.w(TAG, log);
7374         if (mPersistentLogger != null) {
7375             mPersistentLogger.warn(TAG, log);
7376         }
7377     }
7378 
ploge(@onNull String log)7379     private void ploge(@NonNull String log) {
7380         Log.e(TAG, log);
7381         if (mPersistentLogger != null) {
7382             mPersistentLogger.error(TAG, log);
7383         }
7384     }
7385 
plogv(@onNull String log)7386     private void plogv(@NonNull String log) {
7387         Log.v(TAG, log);
7388         if (mPersistentLogger != null) {
7389             mPersistentLogger.debug(TAG, log);
7390         }
7391     }
7392 
handlePersistentLoggingOnSessionStart(RequestSatelliteEnabledArgument argument)7393     private void handlePersistentLoggingOnSessionStart(RequestSatelliteEnabledArgument argument) {
7394         if (mPersistentLogger == null) {
7395             return;
7396         }
7397         if (argument.isEmergency) {
7398             DropBoxManagerLoggerBackend.getInstance(mContext).setLoggingEnabled(true);
7399         }
7400     }
7401 
handlePersistentLoggingOnSessionEnd(boolean isEmergency)7402     private void handlePersistentLoggingOnSessionEnd(boolean isEmergency) {
7403         if (mPersistentLogger == null) {
7404             return;
7405         }
7406         DropBoxManagerLoggerBackend loggerBackend =
7407                 DropBoxManagerLoggerBackend.getInstance(mContext);
7408         // Flush persistent satellite logs on eSOS session end
7409         if (isEmergency) {
7410             loggerBackend.flushAsync();
7411         }
7412         // Also turn off persisted logging until new session is started
7413         loggerBackend.setLoggingEnabled(false);
7414     }
7415 
7416     /**
7417      * Set last emergency call time to the current time.
7418      */
setLastEmergencyCallTime()7419     public void setLastEmergencyCallTime() {
7420         synchronized (mLock) {
7421             mLastEmergencyCallTime = getElapsedRealtime();
7422             plogd("mLastEmergencyCallTime=" + mLastEmergencyCallTime);
7423         }
7424     }
7425 
7426     /**
7427      * Check if satellite is in emergency mode.
7428      */
isInEmergencyMode()7429     public boolean isInEmergencyMode() {
7430         synchronized (mLock) {
7431             if (mLastEmergencyCallTime == 0) return false;
7432 
7433             long currentTime = getElapsedRealtime();
7434             if ((currentTime - mLastEmergencyCallTime) <= mSatelliteEmergencyModeDurationMillis) {
7435                 plogd("Satellite is in emergency mode");
7436                 return true;
7437             }
7438             return false;
7439         }
7440     }
7441 
getSatelliteEmergencyModeDurationFromOverlayConfig(@onNull Context context)7442     private long getSatelliteEmergencyModeDurationFromOverlayConfig(@NonNull Context context) {
7443         Integer duration = DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS;
7444         try {
7445             duration = context.getResources().getInteger(com.android.internal.R.integer
7446                     .config_satellite_emergency_mode_duration);
7447         } catch (Resources.NotFoundException ex) {
7448             ploge("getSatelliteEmergencyModeDurationFromOverlayConfig: got ex=" + ex);
7449         }
7450         return TimeUnit.SECONDS.toMillis(duration);
7451     }
7452 
getEvaluateEsosProfilesPrioritizationDurationMillis()7453     private long getEvaluateEsosProfilesPrioritizationDurationMillis() {
7454         return TimeUnit.MINUTES.toMillis(1);
7455     }
7456 
7457     /**
7458      * Calculate priority
7459      * 1. Active eSOS profiles are higher priority than inactive eSOS profiles.
7460      * 2. Carrier Enabled eSOS profile is higher priority than OEM enabled eSOS profile.
7461      * 3. Among active carrier eSOS profiles user selected(default SMS SIM) eSOS profile will be
7462      * the highest priority.
7463      */
7464     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
evaluateESOSProfilesPrioritization()7465     protected void evaluateESOSProfilesPrioritization() {
7466         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
7467             plogd("evaluateESOSProfilesPrioritization: Flag CarrierRoamingNbIotNtn is disabled");
7468             return;
7469         }
7470 
7471         if (isSatelliteEnabledOrBeingEnabled()) {
7472             plogd("evaluateESOSProfilesPrioritization: Skip evaluation as satellite is enabled "
7473                     + "or being enabled");
7474             return;
7475         }
7476 
7477         boolean isChanged = false;
7478         List<SubscriptionInfo> allSubInfos = mSubscriptionManagerService.getAllSubInfoList(
7479                 mContext.getOpPackageName(), mContext.getAttributionTag());
7480         // Key : priority - lower value has higher priority; Value : List<SubscriptionInfo>
7481         TreeMap<Integer, List<SubscriptionInfo>> newSubsInfoListPerPriority = new TreeMap<>();
7482         plogd("evaluateESOSProfilesPrioritization: allSubInfos.size()=" + allSubInfos.size());
7483         synchronized (mSatelliteTokenProvisionedLock) {
7484             for (SubscriptionInfo info : allSubInfos) {
7485                 int subId = info.getSubscriptionId();
7486                 boolean isActive = info.isActive();
7487                 boolean isDefaultSmsSubId =
7488                         mSubscriptionManagerService.getDefaultSmsSubId() == subId;
7489                 boolean isNtnOnly = info.isOnlyNonTerrestrialNetwork();
7490                 boolean isESOSSupported = info.isSatelliteESOSSupported();
7491                 boolean isCarrierSatelliteHigherPriority =
7492                     isCarrierSatelliteHigherPriority(info);
7493                 if (!isNtnOnly && !isESOSSupported) {
7494                     continue;
7495                 }
7496                 if (!isActive && !isNtnOnly) {
7497                     continue;
7498                 }
7499                 if (!isNtnOnly && !isCarrierConfigLoaded(subId)) {
7500                     // Skip to add priority list if the carrier config is not loaded properly
7501                     // for the given carrier subscription.
7502                     continue;
7503                 }
7504 
7505                 int keyPriority = (isESOSSupported && isActive && isDefaultSmsSubId
7506                     && isCarrierSatelliteHigherPriority)
7507                     ? 0 : (isESOSSupported && isActive &&
7508                         isCarrierSatelliteHigherPriority)
7509                         ? 1 : (isNtnOnly)
7510                             ? 2 : (isESOSSupported)
7511                                 ? 3 : -1;
7512                 if (keyPriority != -1) {
7513                     newSubsInfoListPerPriority.computeIfAbsent(keyPriority,
7514                             k -> new ArrayList<>()).add(info);
7515                 } else {
7516                     plogw("evaluateESOSProfilesPrioritization: Got -1 keyPriority for subId="
7517                             + info.getSubscriptionId());
7518                 }
7519 
7520                 Pair<String, Integer> subscriberIdPair = getSubscriberIdAndType(info);
7521                 String newSubscriberId = subscriberIdPair.first;
7522                 Optional<String> oldSubscriberId = mSubscriberIdPerSub.entrySet().stream()
7523                         .filter(entry -> entry.getValue().equals(subId))
7524                         .map(Map.Entry::getKey).findFirst();
7525 
7526                 if (oldSubscriberId.isPresent()
7527                         && !newSubscriberId.equals(oldSubscriberId.get())) {
7528                     mSubscriberIdPerSub.remove(oldSubscriberId.get());
7529                     mProvisionedSubscriberId.remove(oldSubscriberId.get());
7530                     logd("Old phone number is removed: id = " + subId);
7531                     isChanged = true;
7532                 }
7533                 if (!newSubscriberId.isEmpty()) {
7534                     mSubscriberIdPerSub.put(newSubscriberId, subId);
7535                 }
7536             }
7537         }
7538         plogd("evaluateESOSProfilesPrioritization: newSubsInfoListPerPriority.size()="
7539                   + newSubsInfoListPerPriority.size());
7540 
7541         if (!mHasSentBroadcast && newSubsInfoListPerPriority.size() == 0) {
7542             logd("evaluateESOSProfilesPrioritization: no satellite subscription available");
7543             return;
7544         }
7545 
7546         // If priority has changed, send broadcast for provisioned ESOS subs IDs
7547         synchronized (mSatelliteTokenProvisionedLock) {
7548             List<SatelliteSubscriberProvisionStatus> newEvaluatedSubscriberProvisionStatus =
7549                     getPrioritizedSatelliteSubscriberProvisionStatusList(
7550                             newSubsInfoListPerPriority);
7551             if (isPriorityChanged(mSubsInfoListPerPriority, newSubsInfoListPerPriority)
7552                     || isSubscriberContentChanged(mLastEvaluatedSubscriberProvisionStatus,
7553                             newEvaluatedSubscriberProvisionStatus)
7554                     || isChanged) {
7555                 mSubsInfoListPerPriority = newSubsInfoListPerPriority;
7556                 mLastEvaluatedSubscriberProvisionStatus = newEvaluatedSubscriberProvisionStatus;
7557                 sendBroadCastForProvisionedESOSSubs();
7558                 mHasSentBroadcast = true;
7559                 selectBindingSatelliteSubscription(false);
7560             }
7561         }
7562     }
7563 
7564     // to check if the contents of carrier config is loaded properly
isCarrierConfigLoaded(int subId)7565     private Boolean isCarrierConfigLoaded(int subId) {
7566         PersistableBundle carrierConfig = mCarrierConfigManager
7567                 .getConfigForSubId(subId, KEY_CARRIER_CONFIG_APPLIED_BOOL);
7568         return carrierConfig != null ? carrierConfig.getBoolean(
7569                 CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL) : false;
7570     }
7571 
7572     // The subscriberId for ntnOnly SIMs is the Iccid, whereas for ESOS supported SIMs, the
7573     // subscriberId is the Imsi prefix 6 digit + phone number.
getSubscriberIdAndType(@ullable SubscriptionInfo info)7574     private Pair<String, Integer> getSubscriberIdAndType(@Nullable SubscriptionInfo info) {
7575         String subscriberId = "";
7576         @SatelliteSubscriberInfo.SubscriberIdType int subscriberIdType =
7577                 SatelliteSubscriberInfo.SUBSCRIBER_ID_TYPE_ICCID;
7578         if (info == null) {
7579             logd("getSubscriberIdAndType: subscription info is null");
7580             return new Pair<>(subscriberId, subscriberIdType);
7581         }
7582         if (info.isOnlyNonTerrestrialNetwork()) {
7583             subscriberId = info.getIccId();
7584         } else if (info.isSatelliteESOSSupported()) {
7585             subscriberId = getPhoneNumberBasedCarrier(info.getSubscriptionId());
7586             subscriberIdType = SatelliteSubscriberInfo.SUBSCRIBER_ID_TYPE_IMSI_MSISDN;
7587         }
7588         logd("getSubscriberIdAndType: subscriberId="
7589                 + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, subscriberId)
7590                 + ", subscriberIdType=" + subscriberIdType);
7591         return new Pair<>(subscriberId, subscriberIdType);
7592     }
7593 
7594     /** Get subscriberId from phone number and carrier information. */
7595     @VisibleForTesting(visibility =  VisibleForTesting.Visibility.PRIVATE)
getPhoneNumberBasedCarrier(int subId)7596     public String getPhoneNumberBasedCarrier(int subId) {
7597         String subscriberId = "";
7598         SubscriptionInfoInternal internal = mSubscriptionManagerService.getSubscriptionInfoInternal(
7599                 subId);
7600         if (internal == null) {
7601             plogd("getPhoneNumberBasedCarrier: subscriptionInfoInternal is null.");
7602             return subscriberId;
7603         }
7604 
7605         SubscriptionManager subscriptionManager = mContext.getSystemService(
7606                 SubscriptionManager.class);
7607         if (mInjectSubscriptionManager != null) {
7608             plogd("getPhoneNumberBasedCarrier: InjectSubscriptionManager");
7609             subscriptionManager = mInjectSubscriptionManager;
7610         }
7611 
7612         if (subscriptionManager == null) {
7613             plogd("getPhoneNumberBasedCarrier: subscriptionManager is null");
7614             return subscriberId;
7615         }
7616 
7617         String phoneNumber = subscriptionManager.getPhoneNumber(subId);
7618         if (TextUtils.isEmpty(phoneNumber)) {
7619             plogd("getPhoneNumberBasedCarrier: phoneNumber is empty.");
7620             return subscriberId;
7621         }
7622 
7623         String imsi = internal.getImsi();
7624         if (TextUtils.isEmpty(imsi)) {
7625             plogd("getPhoneNumberBasedCarrier: imsi is empty");
7626             return subscriberId;
7627         }
7628 
7629         if (imsi.length() < 6) {
7630             plogd("getPhoneNumberBasedCarrier: imsi length is less than 6");
7631             return subscriberId;
7632         }
7633 
7634         subscriberId = internal.getImsi().substring(0, 6)
7635                 + phoneNumber.replaceFirst("^\\+", "");
7636         plogd("getPhoneNumberBasedCarrier: subscriberId="
7637                 + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, subscriberId));
7638         return subscriberId;
7639     }
7640 
isPriorityChanged(Map<Integer, List<SubscriptionInfo>> currentMap, Map<Integer, List<SubscriptionInfo>> newMap)7641     private boolean isPriorityChanged(Map<Integer, List<SubscriptionInfo>> currentMap,
7642             Map<Integer, List<SubscriptionInfo>> newMap) {
7643         if (currentMap.size() == 0 || currentMap.size() != newMap.size()) {
7644             return true;
7645         }
7646 
7647         for (Map.Entry<Integer, List<SubscriptionInfo>> entry : currentMap.entrySet()) {
7648             List<SubscriptionInfo> currentList = entry.getValue();
7649             List<SubscriptionInfo> newList = newMap.get(entry.getKey());
7650             if (newList == null || currentList == null || currentList.size() != newList.size()) {
7651                 return true;
7652             }
7653             for (int i = 0; i < currentList.size(); i++) {
7654                 if (currentList.get(i).getSubscriptionId() != newList.get(i).getSubscriptionId()) {
7655                     logd("isPriorityChanged: cur=" + currentList.get(i) + " , new=" + newList.get(
7656                             i));
7657                     return true;
7658                 }
7659             }
7660         }
7661         return false;
7662     }
7663 
7664     // Checks if there are any changes between subscriberInfos. return false if the same.
7665     // Note that, Use lists with the same priority so we can compare contents properly.
isSubscriberContentChanged(List<SatelliteSubscriberProvisionStatus> currentList, List<SatelliteSubscriberProvisionStatus> newList)7666     private boolean isSubscriberContentChanged(List<SatelliteSubscriberProvisionStatus> currentList,
7667             List<SatelliteSubscriberProvisionStatus> newList) {
7668         if (currentList.size() != newList.size()) {
7669             return true;
7670         }
7671         for (int i = 0; i < currentList.size(); i++) {
7672             SatelliteSubscriberProvisionStatus curSub = currentList.get(i);
7673             SatelliteSubscriberProvisionStatus newSub = newList.get(i);
7674             if (!curSub.getSatelliteSubscriberInfo().equals(newSub.getSatelliteSubscriberInfo())) {
7675                 logd("isSubscriberContentChanged: cur=" + curSub + " , new=" + newSub);
7676                 return true;
7677             }
7678         }
7679         return false;
7680     }
7681 
sendBroadCastForProvisionedESOSSubs()7682     private void sendBroadCastForProvisionedESOSSubs() {
7683         String packageName = getConfigSatelliteGatewayServicePackage();
7684         String className = getConfigSatelliteCarrierRoamingEsosProvisionedClass();
7685         if (packageName == null || className == null || packageName.isEmpty()
7686                 || className.isEmpty()) {
7687             logd("sendBroadCastForProvisionedESOSSubs: packageName or className is null or empty.");
7688             return;
7689         }
7690         String action = SatelliteManager.ACTION_SATELLITE_SUBSCRIBER_ID_LIST_CHANGED;
7691 
7692         Intent intent = new Intent(action);
7693         intent.setComponent(new ComponentName(packageName, className));
7694         if (mFeatureFlags.hsumBroadcast()) {
7695             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
7696         } else {
7697             mContext.sendBroadcast(intent);
7698         }
7699         logd("sendBroadCastForProvisionedESOSSubs" + intent);
7700     }
7701 
7702     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getStringFromOverlayConfig(int resourceId)7703     protected String getStringFromOverlayConfig(int resourceId) {
7704         String name;
7705         try {
7706             name = mContext.getResources().getString(resourceId);
7707         } catch (Resources.NotFoundException ex) {
7708             loge("getStringFromOverlayConfig: ex=" + ex);
7709             name = null;
7710         }
7711         return name;
7712     }
7713 
7714     /**
7715      * Request to get the name to display for Satellite.
7716      *
7717      * @param result The result receiver that returns the name to display for the satellite
7718      *               or an error code if the request failed.
7719      */
requestSatelliteDisplayName(@onNull ResultReceiver result)7720     public void requestSatelliteDisplayName(@NonNull ResultReceiver result) {
7721         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
7722             plogd("requestSatelliteDisplayName: carrierRoamingNbIotNtn flag is disabled");
7723             result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
7724             return;
7725         }
7726 
7727         int subId = getSelectedSatelliteSubId();
7728         String displayName = getConfigForSubId(subId).getString(
7729                 KEY_SATELLITE_DISPLAY_NAME_STRING, "Satellite");
7730 
7731         plogd("requestSatelliteDisplayName: " + displayName);
7732         Bundle bundle = new Bundle();
7733         bundle.putString(SatelliteManager.KEY_SATELLITE_DISPLAY_NAME, displayName);
7734         result.send(SATELLITE_RESULT_SUCCESS, bundle);
7735     }
7736 
7737     /**
7738      * Request to get list of prioritized satellite tokens to be used for provision.
7739      *
7740      * @param result The result receiver, which returns the list of prioritized satellite tokens
7741      * to be used for provision if the request is successful or an error code if the request failed.
7742      */
requestSatelliteSubscriberProvisionStatus(@onNull ResultReceiver result)7743     public void requestSatelliteSubscriberProvisionStatus(@NonNull ResultReceiver result) {
7744         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
7745             logd("requestSatelliteSubscriberProvisionStatus: carrierRoamingNbIotNtn is disabled");
7746             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
7747             return;
7748         }
7749         List<SatelliteSubscriberProvisionStatus> list =
7750                 getPrioritizedSatelliteSubscriberProvisionStatusList();
7751         logd("requestSatelliteSubscriberProvisionStatus: " + list);
7752         final Bundle bundle = new Bundle();
7753         bundle.putParcelableList(SatelliteManager.KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN, list);
7754         result.send(SATELLITE_RESULT_SUCCESS, bundle);
7755     }
7756 
7757     private List<SatelliteSubscriberProvisionStatus>
getPrioritizedSatelliteSubscriberProvisionStatusList()7758             getPrioritizedSatelliteSubscriberProvisionStatusList() {
7759         synchronized (mSatelliteTokenProvisionedLock) {
7760             return getPrioritizedSatelliteSubscriberProvisionStatusList(mSubsInfoListPerPriority);
7761         }
7762     }
7763 
7764     private List<SatelliteSubscriberProvisionStatus>
getPrioritizedSatelliteSubscriberProvisionStatusList( Map<Integer, List<SubscriptionInfo>> subsInfoListPerPriority)7765             getPrioritizedSatelliteSubscriberProvisionStatusList(
7766                     Map<Integer, List<SubscriptionInfo>> subsInfoListPerPriority) {
7767         List<SatelliteSubscriberProvisionStatus> list = new ArrayList<>();
7768         synchronized (mSatelliteTokenProvisionedLock) {
7769             for (int priority : subsInfoListPerPriority.keySet()) {
7770                 List<SubscriptionInfo> infoList = subsInfoListPerPriority.get(priority);
7771                 if (infoList == null) {
7772                     logd("getPrioritySatelliteSubscriberProvisionStatusList: no exist this "
7773                             + "priority " + priority);
7774                     continue;
7775                 }
7776                 for (SubscriptionInfo info : infoList) {
7777                     Pair<String, Integer> subscriberIdPair = getSubscriberIdAndType(info);
7778                     String subscriberId = subscriberIdPair.first;
7779                     int carrierId = info.getCarrierId();
7780                     String apn = getConfigForSubId(info.getSubscriptionId())
7781                             .getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
7782                     logd("getPrioritySatelliteSubscriberProvisionStatusList:"
7783                             + " subscriberId:"
7784                             + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, subscriberId)
7785                             + " , carrierId=" + carrierId + " , apn=" + apn);
7786                     if (subscriberId.isEmpty()) {
7787                         logd("getPrioritySatelliteSubscriberProvisionStatusList: getSubscriberId "
7788                                 + "failed skip this subscriberId.");
7789                         continue;
7790                     }
7791                     SatelliteSubscriberInfo satelliteSubscriberInfo =
7792                             new SatelliteSubscriberInfo.Builder().setSubscriberId(subscriberId)
7793                                     .setCarrierId(carrierId).setNiddApn(apn)
7794                                     .setSubscriptionId(info.getSubscriptionId())
7795                                     .setSubscriberIdType(subscriberIdPair.second)
7796                                     .build();
7797                     boolean provisioned = mProvisionedSubscriberId.getOrDefault(subscriberId,
7798                             false);
7799                     logd("getPrioritySatelliteSubscriberProvisionStatusList: "
7800                             + "satelliteSubscriberInfo=" + satelliteSubscriberInfo
7801                             + ", provisioned=" + provisioned);
7802                     list.add(new SatelliteSubscriberProvisionStatus.Builder()
7803                             .setSatelliteSubscriberInfo(satelliteSubscriberInfo)
7804                             .setProvisioned(provisioned).build());
7805                     mSubscriberIdPerSub.put(subscriberId, info.getSubscriptionId());
7806                 }
7807             }
7808         }
7809         return list;
7810     }
7811 
getSelectedSatelliteSubId()7812     public int getSelectedSatelliteSubId() {
7813         plogd("getSelectedSatelliteSubId: subId=" + mSelectedSatelliteSubId);
7814         return mSelectedSatelliteSubId;
7815     }
7816 
7817     /**
7818      * Request to get the currently selected satellite subscription id.
7819      *
7820      * @param result The result receiver that returns the currently selected satellite subscription
7821      *               id if the request is successful or an error code if the request failed.
7822      */
requestSelectedNbIotSatelliteSubscriptionId(@onNull ResultReceiver result)7823     public void requestSelectedNbIotSatelliteSubscriptionId(@NonNull ResultReceiver result) {
7824         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
7825             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
7826             logd("requestSelectedNbIotSatelliteSubscriptionId: carrierRoamingNbIotNtn is disabled");
7827             return;
7828         }
7829 
7830         int selectedSatelliteSubId = getSelectedSatelliteSubId();
7831         plogd("requestSelectedNbIotSatelliteSubscriptionId: " + selectedSatelliteSubId);
7832         if (selectedSatelliteSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
7833             result.send(SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION, null);
7834             logd("requestSelectedNbIotSatelliteSubscriptionId: "
7835                     + "selectedSatelliteSubId is invalid");
7836             return;
7837         }
7838 
7839         Bundle bundle = new Bundle();
7840         bundle.putInt(SatelliteManager.KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID,
7841                 selectedSatelliteSubId);
7842         result.send(SATELLITE_RESULT_SUCCESS, bundle);
7843     }
7844 
selectBindingSatelliteSubscription(boolean shouldIgnoreEnabledState)7845     private void selectBindingSatelliteSubscription(boolean shouldIgnoreEnabledState) {
7846         if ((isSatelliteEnabled() || isSatelliteBeingEnabled()) && !shouldIgnoreEnabledState) {
7847             plogd("selectBindingSatelliteSubscription: satellite subscription will be selected "
7848                     + "once the satellite session ends");
7849             return;
7850         }
7851 
7852         int selectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
7853         List<SatelliteSubscriberProvisionStatus> satelliteSubscribers =
7854                 getPrioritizedSatelliteSubscriberProvisionStatusList();
7855 
7856         for (SatelliteSubscriberProvisionStatus status : satelliteSubscribers) {
7857             int subId = getSubIdFromSubscriberId(
7858                     status.getSatelliteSubscriberInfo().getSubscriberId());
7859 
7860             if (status.isProvisioned() && isActiveSubId(subId) &&
7861                 isSatelliteAvailableAtCurrentLocation(
7862                     mSubscriptionManagerService.getSubscriptionInfo(subId))) {
7863                 selectedSubId = subId;
7864                 break;
7865             }
7866         }
7867 
7868         if (selectedSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
7869                 && isSatelliteSupportedViaOem()) {
7870             selectedSubId = getNtnOnlySubscriptionId();
7871         }
7872 
7873         int preSelectedSatelliteSubId = getSelectedSatelliteSubId();
7874         setSelectedSatelliteSubId(selectedSubId);
7875         if (preSelectedSatelliteSubId != getSelectedSatelliteSubId()) {
7876             plogd("selectBindingSatelliteSubscription: SelectedSatelliteSubId changed");
7877             mSatelliteSubIdChangedRegistrants.notifyRegistrants();
7878             handleEventSelectedNbIotSatelliteSubscriptionChanged(selectedSubId);
7879             handleCarrierRoamingNtnAvailableServicesChanged();
7880             evaluateCarrierRoamingNtnEligibilityChange();
7881         }
7882 
7883         setSatellitePhone(selectedSubId);
7884         if (selectedSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
7885             int carrierId = getSatelliteCarrierId();
7886             if (carrierId != UNKNOWN_CARRIER_ID) {
7887                 mControllerMetricsStats.setCarrierId(carrierId);
7888             } else {
7889                 logd("selectBindingSatelliteSubscription: Carrier ID is UNKNOWN_CARRIER_ID");
7890             }
7891             mControllerMetricsStats.setIsNtnOnlyCarrier(isNtnOnlyCarrier());
7892         }
7893         plogd("selectBindingSatelliteSubscription: SelectedSatelliteSubId=" + selectedSubId);
7894     }
7895 
7896     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
isCarrierSatelliteHigherPriority(SubscriptionInfo info)7897     protected boolean isCarrierSatelliteHigherPriority(SubscriptionInfo info) {
7898         if(!isSatelliteAccessAllowedAtCurrentLocation()) {
7899             return true;
7900         }
7901         if(isSatelliteAvailableAtCurrentLocation(info)) {
7902             return true;
7903         }
7904         return false;
7905     }
7906 
7907     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
isSatelliteAvailableAtCurrentLocation(@ullable SubscriptionInfo info)7908     protected boolean isSatelliteAvailableAtCurrentLocation(@Nullable SubscriptionInfo info) {
7909         if(info == null) {
7910             plogd("isSatelliteAvailableAtCurrentLocation: subscriptionInfo is null");
7911             return false;
7912         }
7913         if (mCtsSatelliteAccessAllowedSubIds.contains(info.getSubscriptionId())) {
7914             plogd("isSatelliteAvailableAtCurrentLocation: subscriptionId="
7915                       + info.getSubscriptionId() + " is allowed for CTS testing");
7916             return true;
7917         }
7918         if (!isSatelliteAccessAllowedAtCurrentLocation()) {
7919             plogd("isSatelliteAvailableAtCurrentLocation: satellite access is not allowed at " +
7920                     "current location");
7921             return false;
7922         }
7923         if(info.isOnlyNonTerrestrialNetwork()) {
7924             return true;
7925         }
7926 
7927         int[] carrierTagIdsArray = mContext.getResources().getIntArray(
7928             R.array.config_verizon_satellite_enabled_tagids);
7929         List<Integer> carrierTagIds = null;
7930 
7931         if(carrierTagIdsArray != null && carrierTagIdsArray.length > 0) {
7932             carrierTagIds = Arrays.stream(carrierTagIdsArray)
7933                 .boxed()
7934                 .collect(Collectors.toList());
7935         }
7936 
7937         if(carrierTagIds == null) {
7938             String satelliteAccessConfigFile =
7939                 getSatelliteAccessConfigurationFileFromOverlayConfig();
7940             if (TextUtils.isEmpty(satelliteAccessConfigFile)) {
7941                 plogd("isSatelliteAvailableAtCurrentLocation: device does not support"
7942                           + " custom satellite access configuration per location");
7943                 return true;
7944             } else {
7945                 plogd("isSatelliteAvailableAtCurrentLocation: tagids for carrier "
7946                           + info.getCarrierName() + ", subId=" + info.getSubscriptionId()
7947                           + " are not available");
7948                 return false;
7949             }
7950         }
7951 
7952         return isCarrierSatelliteAvailableAtCurrentLocation(carrierTagIds);
7953     }
7954 
7955     @Nullable
getSatelliteAccessConfigurationFileFromOverlayConfig()7956     private String getSatelliteAccessConfigurationFileFromOverlayConfig() {
7957         String satelliteAccessConfigFile = null;
7958         try {
7959             satelliteAccessConfigFile = mContext.getResources().getString(
7960                     com.android.internal.R.string.satellite_access_config_file);
7961         } catch (Resources.NotFoundException ex) {
7962             loge("getSatelliteAccessConfigurationFileFromOverlayConfig: got ex=" + ex);
7963         }
7964 
7965         logd("satelliteAccessConfigFile =" + satelliteAccessConfigFile);
7966         return satelliteAccessConfigFile;
7967     }
7968 
7969     /**
7970      * Compares tagIds and determine if
7971      * carrier satellite is available at current location while selecting highest priority profile.
7972      *
7973      * @param carrierTagIds a list of integer tagIds representing regions where carrier satellite
7974      * coverage is available.
7975      * @return {@code true} if the carrier satellite is available at current location,
7976      *      {@code false} otherwise.
7977      */
isCarrierSatelliteAvailableAtCurrentLocation( List<Integer> carrierTagIds)7978     public boolean isCarrierSatelliteAvailableAtCurrentLocation(
7979         List<Integer> carrierTagIds) {
7980         synchronized (mSatelliteAccessConfigLock) {
7981             return !Collections.disjoint(carrierTagIds, mCurrentLocationTagIds);
7982         }
7983     }
7984 
getSubIdFromSubscriberId(String subscriberId)7985     private int getSubIdFromSubscriberId(String subscriberId) {
7986         synchronized (mSatelliteTokenProvisionedLock) {
7987             return mSubscriberIdPerSub.getOrDefault(subscriberId,
7988                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
7989         }
7990     }
7991 
isActiveSubId(int subId)7992     private boolean isActiveSubId(int subId) {
7993         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
7994         if (subInfo == null) {
7995             logd("isActiveSubId: subscription associated with subId=" + subId + " not found");
7996             return false;
7997         }
7998         return subInfo.isActive();
7999     }
8000 
8001     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isSubscriptionProvisioned(int subId)8002     protected boolean isSubscriptionProvisioned(int subId) {
8003         plogd("isSubscriptionProvisioned: subId=" + subId);
8004         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8005             plogd("isSubscriptionProvisioned: carrierRoamingNbIotNtn flag is disabled");
8006             return false;
8007         }
8008 
8009         String subscriberId = getSubscriberIdAndType(
8010                 mSubscriptionManagerService.getSubscriptionInfo(subId)).first;
8011         if (subscriberId.isEmpty()) {
8012             plogd("isSubscriptionProvisioned: subId=" + subId + " subscriberId is empty.");
8013             return false;
8014         }
8015 
8016         synchronized (mSatelliteTokenProvisionedLock) {
8017             return mProvisionedSubscriberId.getOrDefault(subscriberId, false);
8018         }
8019     }
8020 
8021     /**
8022      * Deliver the list of provisioned satellite subscriber ids.
8023      *
8024      * @param list List of provisioned satellite subscriber ids.
8025      * @param result The result receiver that returns whether deliver success or fail.
8026      */
provisionSatellite(@onNull List<SatelliteSubscriberInfo> list, @NonNull ResultReceiver result)8027     public void provisionSatellite(@NonNull List<SatelliteSubscriberInfo> list,
8028             @NonNull ResultReceiver result) {
8029         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8030             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
8031             logd("provisionSatellite: carrierRoamingNbIotNtn not support");
8032             return;
8033         }
8034         if (list.isEmpty()) {
8035             result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null);
8036             logd("provisionSatellite: SatelliteSubscriberInfo list is empty");
8037             return;
8038         }
8039 
8040         logd("provisionSatellite:" + list);
8041         RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list,
8042                 result, true);
8043         sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null);
8044         incrementResultReceiverCount("SC:provisionSatellite");
8045     }
8046 
8047     /**
8048      * Request to update system selection channels.
8049      *
8050      * @param result The result receiver that returns if the request is successful or
8051      *               an error code if the request failed.
8052      */
updateSystemSelectionChannels( @onNull List<SystemSelectionSpecifier> selectionSpecifiers, @NonNull ResultReceiver result)8053     public void updateSystemSelectionChannels(
8054             @NonNull List<SystemSelectionSpecifier> selectionSpecifiers,
8055             @NonNull ResultReceiver result) {
8056         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8057             plogd("updateSystemSelectionChannels: "
8058                     + "carrierRoamingNbIotNtn flag is disabled");
8059             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
8060             return;
8061         }
8062 
8063         sendRequestAsync(CMD_UPDATE_SYSTEM_SELECTION_CHANNELS,
8064                 new UpdateSystemSelectionChannelsArgument(selectionSpecifiers, result), null);
8065     }
8066 
8067     /**
8068      * @param subId Subscription ID.
8069      * @return The The map of earfcns with key: regional satellite config Id,
8070      * value: set of earfcns in the corresponding regions associated with the {@code subId}.
8071      */
8072     @NonNull
getRegionalSatelliteEarfcns(int subId)8073     public Map<String, Set<Integer>> getRegionalSatelliteEarfcns(int subId) {
8074         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8075             logd("getRegionalSatelliteEarfcns: carrierRoamingNbIotNtnFlag is disabled");
8076             return new HashMap<>();
8077         }
8078         synchronized (mRegionalSatelliteEarfcnsLock) {
8079             if (mRegionalSatelliteEarfcns.containsKey(subId)) {
8080                 return mRegionalSatelliteEarfcns.get(subId);
8081             } else {
8082                 logd("getRegionalSatelliteEarfcns: Earfcns for subId: " + subId + " not found");
8083                 return new HashMap<>();
8084             }
8085         }
8086     }
8087 
8088     /**
8089      * Update regional satellite earfcn information from carrier config.
8090      */
updateRegionalSatelliteEarfcns(int subId)8091     public void updateRegionalSatelliteEarfcns(int subId) {
8092         plogd("updateRegionalSatelliteEarfcns with subId " + subId);
8093         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8094             plogd("updateRegionalSatelliteEarfcns: "
8095                     + "carrierRoamingNbIotNtn flag is disabled");
8096             return;
8097         }
8098 
8099         synchronized (mRegionalSatelliteEarfcnsLock) {
8100             mRegionalSatelliteEarfcns.put(subId,
8101                     readRegionalSatelliteEarfcnsFromCarrierConfig(subId));
8102         }
8103     }
8104 
8105     /**
8106      * Deliver the list of deprovisioned satellite subscriber ids.
8107      *
8108      * @param list List of deprovisioned satellite subscriber ids.
8109      * @param result The result receiver that returns whether deliver success or fail.
8110      */
deprovisionSatellite(@onNull List<SatelliteSubscriberInfo> list, @NonNull ResultReceiver result)8111     public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list,
8112             @NonNull ResultReceiver result) {
8113         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8114             result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
8115             logd("deprovisionSatellite: carrierRoamingNbIotNtn not support");
8116             return;
8117         }
8118         if (list.isEmpty()) {
8119             result.send(SATELLITE_RESULT_INVALID_ARGUMENTS, null);
8120             logd("deprovisionSatellite: SatelliteSubscriberInfo list is empty");
8121             return;
8122         }
8123 
8124         logd("deprovisionSatellite:" + list);
8125         RequestProvisionSatelliteArgument request = new RequestProvisionSatelliteArgument(list,
8126                 result, false);
8127         sendRequestAsync(CMD_UPDATE_PROVISION_SATELLITE_TOKEN, request, null);
8128         incrementResultReceiverCount("SC:provisionSatellite");
8129     }
8130 
8131     /**
8132      * Inform whether application supports NTN SMS in satellite mode.
8133      *
8134      * This method is used by default messaging application to inform framework whether it supports
8135      * NTN SMS or not.
8136      *
8137      * @param ntnSmsSupported {@code true} If application supports NTN SMS, else {@code false}.
8138      */
setNtnSmsSupportedByMessagesApp(boolean ntnSmsSupported)8139     public void setNtnSmsSupportedByMessagesApp(boolean ntnSmsSupported) {
8140         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8141             return;
8142         }
8143         persistNtnSmsSupportedByMessagesApp(ntnSmsSupported);
8144         handleCarrierRoamingNtnAvailableServicesChanged();
8145     }
8146 
persistNtnSmsSupportedByMessagesApp(boolean ntnSmsSupported)8147     private void persistNtnSmsSupportedByMessagesApp(boolean ntnSmsSupported) {
8148         plogd("persistNtnSmsSupportedByMessagesApp: ntnSmsSupported=" + ntnSmsSupported);
8149         if (!loadSatelliteSharedPreferences()) return;
8150 
8151         if (mSharedPreferences == null) {
8152             ploge("persistNtnSmsSupportedByMessagesApp: mSharedPreferences is null");
8153         } else {
8154             mSharedPreferences.edit().putBoolean(
8155                     NTN_SMS_SUPPORTED_BY_MESSAGES_APP_KEY, ntnSmsSupported).apply();
8156             synchronized (mNtnSmsSupportedByMessagesAppLock) {
8157                 mNtnSmsSupportedByMessagesApp = ntnSmsSupported;
8158             }
8159         }
8160     }
8161 
isNtnSmsSupportedByMessagesApp()8162     private boolean isNtnSmsSupportedByMessagesApp() {
8163         synchronized (mNtnSmsSupportedByMessagesAppLock) {
8164             if (mNtnSmsSupportedByMessagesApp != null) {
8165                 plogd("isNtnSmsSupportedByMessagesApp:" + mNtnSmsSupportedByMessagesApp);
8166                 return mNtnSmsSupportedByMessagesApp;
8167             }
8168         }
8169 
8170         if (!loadSatelliteSharedPreferences()) return false;
8171 
8172         if (mSharedPreferences == null) {
8173             ploge("isNtnSmsSupportedByMessagesApp: mSharedPreferences is null");
8174             return false;
8175         } else {
8176             boolean ntnSmsSupported = mSharedPreferences.getBoolean(
8177                     NTN_SMS_SUPPORTED_BY_MESSAGES_APP_KEY, false);
8178             synchronized (mNtnSmsSupportedByMessagesAppLock) {
8179                 mNtnSmsSupportedByMessagesApp = ntnSmsSupported;
8180                 plogd("isNtnSmsSupportedByMessagesApp:" + mNtnSmsSupportedByMessagesApp);
8181             }
8182             return ntnSmsSupported;
8183         }
8184     }
8185 
8186     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSatellitePhone(int subId)8187     protected void setSatellitePhone(int subId) {
8188         synchronized (mSatellitePhoneLock) {
8189             mSatellitePhone = SatelliteServiceUtils.getPhone(subId);
8190             plogd("mSatellitePhone: phoneId=" + (mSatellitePhone != null
8191                       ? mSatellitePhone.getPhoneId() : "null") + ", subId=" + subId);
8192         }
8193     }
8194 
8195     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSelectedSatelliteSubId(int subId)8196     protected void setSelectedSatelliteSubId(int subId) {
8197         synchronized (mSatelliteTokenProvisionedLock) {
8198             plogd("setSelectedSatelliteSubId: subId=" + subId);
8199             mSelectedSatelliteSubId = subId;
8200         }
8201     }
8202 
8203     /** Return the carrier ID of the binding satellite subscription. */
getSatelliteCarrierId()8204     public int getSatelliteCarrierId() {
8205         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(
8206             mSelectedSatelliteSubId);
8207         if (subInfo == null) {
8208             logd("getSatelliteCarrierId: returns UNKNOWN_CARRIER_ID");
8209             return UNKNOWN_CARRIER_ID;
8210         }
8211         return subInfo.getCarrierId();
8212     }
8213 
8214     /**
8215      * Get whether phone is eligible to connect to carrier roaming non-terrestrial network.
8216      *
8217      * @param phone phone object
8218      * return {@code true} when the subscription is eligible for satellite
8219      * communication if all the following conditions are met:
8220      * <ul>
8221      * <li>Subscription supports P2P satellite messaging which is defined by
8222      * {@link CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} </li>
8223      * <li>{@link CarrierConfigManager#KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT} set to
8224      * {@link CarrierConfigManager#CARRIER_ROAMING_NTN_CONNECT_MANUAL} </li>
8225      * <li>The device is in {@link ServiceState#STATE_OUT_OF_SERVICE}, not connected to Wi-Fi. </li>
8226      * </ul>
8227      */
8228     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isCarrierRoamingNtnEligible(@ullable Phone phone)8229     public boolean isCarrierRoamingNtnEligible(@Nullable Phone phone) {
8230         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8231             plogd("isCarrierRoamingNtnEligible: carrierRoamingNbIotNtn flag is disabled");
8232             return false;
8233         }
8234 
8235         if (!mIsRadioOn) {
8236             plogd("isCarrierRoamingNtnEligible: radio is off");
8237             return false;
8238         }
8239 
8240         boolean isSatelliteAccessAllowed = isSatelliteAccessAllowedAtCurrentLocation();
8241         if (!isSatelliteAccessAllowed) {
8242             plogd("isCarrierRoamingNtnEligible: satellite access is not allowed");
8243             return false;
8244         }
8245 
8246         // Even if Location service is off, isSatelliteAccessAllowed can be true
8247         // when the device is in emergency call and the allowed cache is valid.
8248         if (!isLocationServiceEnabled()) {
8249             plogd("isCarrierRoamingNtnEligible: Location service is off");
8250             return false;
8251         }
8252 
8253         if (phone == null) {
8254             plogd("isCarrierRoamingNtnEligible: phone is null");
8255             return false;
8256         }
8257 
8258         int subId = getSelectedSatelliteSubId();
8259         if (!isSatelliteRoamingP2pSmSSupported(subId)) {
8260             plogd("isCarrierRoamingNtnEligible(" + subId + "): doesn't support P2P SMS");
8261             return false;
8262         }
8263 
8264         if (!isSatelliteSupportedViaCarrier(subId)) {
8265             plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
8266                     + "]: satellite is not supported via carrier");
8267             return false;
8268         }
8269 
8270         if (!isSubscriptionProvisioned(subId)) {
8271             plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
8272                     + "]: subscription is not provisioned to use satellite.");
8273             return false;
8274         }
8275 
8276         int[] services = getSupportedServicesOnCarrierRoamingNtn(subId);
8277         if (!ArrayUtils.contains(services, NetworkRegistrationInfo.SERVICE_TYPE_SMS)) {
8278             plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
8279                     + "]: SMS is not supported by carrier");
8280             return false;
8281         }
8282 
8283         int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
8284         if (carrierRoamingNtnConnectType != CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
8285             plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId() + "]: not manual "
8286                     + "connect. carrierRoamingNtnConnectType = " + carrierRoamingNtnConnectType);
8287             return false;
8288         }
8289 
8290         if (mOverrideNtnEligibility != null) {
8291             // TODO need to send the value from `mOverrideNtnEligibility` or simply true ?
8292             return true;
8293         }
8294 
8295         if (SatelliteServiceUtils.isCellularAvailable()) {
8296             plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
8297                     + "]: cellular is available");
8298             return false;
8299         }
8300 
8301         synchronized (mIsWifiConnectedLock) {
8302             if (mIsWifiConnected) {
8303                 plogd("isCarrierRoamingNtnEligible[phoneId=" + phone.getPhoneId()
8304                         + "]: Wi-Fi is connected");
8305                 return false;
8306             }
8307         }
8308 
8309         return true;
8310     }
8311 
8312 
8313     /**
8314      * Checks if the satellite service is supported by the carrier for the specified
8315      * subscription ID and servicetype.
8316      *
8317      * @param subId The subscription id.
8318      * @param serviceType The type of service to check
8319      */
isSatelliteServiceSupportedByCarrier(int subId, @NetworkRegistrationInfo.ServiceType int serviceType)8320     public boolean isSatelliteServiceSupportedByCarrier(int subId,
8321             @NetworkRegistrationInfo.ServiceType int serviceType) {
8322         List<String> satellitePlmnList = getSatellitePlmnsForCarrier(subId);
8323         for (String satellitePlmn : satellitePlmnList) {
8324             if (getSupportedSatelliteServicesForPlmn(subId, satellitePlmn).contains(serviceType)) {
8325                 return true;
8326             }
8327         }
8328         return false;
8329     }
8330 
8331     /** return satellite phone */
8332     @Nullable
getSatellitePhone()8333     public Phone getSatellitePhone() {
8334         synchronized (mSatellitePhoneLock) {
8335             return mSatellitePhone;
8336         }
8337     }
8338 
8339     /** Start PointingUI if it is required. */
startPointingUI()8340     public void startPointingUI() {
8341         synchronized (mNeedsSatellitePointingLock) {
8342             plogd("startPointingUI: mNeedsSatellitePointing=" + mNeedsSatellitePointing
8343                     + ", mIsDemoModeEnabled=" + mIsDemoModeEnabled
8344                     + ", mIsEmergency=" + mIsEmergency);
8345             if (mNeedsSatellitePointing) {
8346                 mPointingAppController.startPointingUI(false /*needFullScreenPointingUI*/,
8347                         mIsDemoModeEnabled, mIsEmergency);
8348             }
8349         }
8350     }
8351 
8352     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
registerForSatelliteCommunicationAccessStateChanged()8353     protected void registerForSatelliteCommunicationAccessStateChanged() {
8354         if (mRegisteredForSatelliteCommunicationAccessStateChanged.get()) {
8355             if (DEBUG) {
8356                 plogd("registerForSatelliteCommunicationAccessStateChanged: already registered.");
8357             }
8358             return;
8359         }
8360 
8361         SatelliteManager satelliteManager = mContext.getSystemService(SatelliteManager.class);
8362         if (satelliteManager == null) {
8363             ploge("registerForSatelliteCommunicationAccessStateChanged: SatelliteManager is null");
8364             return;
8365         }
8366 
8367         SatelliteCommunicationAccessStateCallback accessStateCallback =
8368             new SatelliteCommunicationAccessStateCallback() {
8369                 @Override
8370                 public void onAccessAllowedStateChanged(boolean isAllowed) {
8371                     plogd("onAccessStateChanged: isAllowed=" + isAllowed);
8372                     if (mFeatureFlags.satelliteExitP2pSessionOutsideGeofence()) {
8373                         handleSatelliteAccessAllowedStateChanged(isAllowed);
8374                     } else{
8375                         synchronized (mSatelliteAccessConfigLock) {
8376                             mSatelliteAccessAllowed = isAllowed;
8377                         }
8378                         evaluateESOSProfilesPrioritization();
8379                         evaluateCarrierRoamingNtnEligibilityChange();
8380                         handleCarrierRoamingNtnAvailableServicesChanged();
8381                     }
8382                 }
8383 
8384                 @Override
8385                 public void onAccessConfigurationChanged(
8386                     SatelliteAccessConfiguration satelliteAccessConfiguration) {
8387                     plogd("onAccessConfigurationChanged: satelliteAccessConfiguration="
8388                         + satelliteAccessConfiguration);
8389                     handleSatelliteAccessConfigUpdateResult(satelliteAccessConfiguration);
8390                 }
8391             };
8392         try {
8393             satelliteManager.registerForCommunicationAccessStateChanged(
8394                     this::post, accessStateCallback);
8395         } catch(RuntimeException e) {
8396             plogd("registerForSatelliteCommunicationAccessStateChanged: "
8397                     + "satelliteManager.registerForCommunicationAccessStateChanged() failed, "
8398                     + "e=" + e);
8399             return;
8400         }
8401         mRegisteredForSatelliteCommunicationAccessStateChanged.set(true);
8402     }
8403 
8404     /** Handle access allowed state changes. */
8405     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
handleSatelliteAccessAllowedStateChanged(boolean isAllowed)8406     public void handleSatelliteAccessAllowedStateChanged(boolean isAllowed) {
8407         plogd("handleSatelliteAccessAllowedStateChanged: isAllowed=" + isAllowed);
8408         synchronized (mSatelliteAccessConfigLock) {
8409             mSatelliteAccessAllowed = isAllowed;
8410         }
8411 
8412         evaluateESOSProfilesPrioritization();
8413         selectBindingSatelliteSubscription(false);
8414         evaluateCarrierRoamingNtnEligibilityChange();
8415         handleCarrierRoamingNtnAvailableServicesChanged();
8416         evaluateDisablingP2pSession();
8417     }
8418 
evaluateDisablingP2pSession()8419     private void evaluateDisablingP2pSession() {
8420         boolean isAllowed = isSatelliteAccessAllowedAtCurrentLocation();
8421         boolean isSatelliteEnabled = isSatelliteEnabled();
8422         boolean isEmergency = getRequestIsEmergency();
8423 
8424         plogd("evaluateDisablingP2pSession: isAllowed=" + isAllowed
8425                 + " isEmergency=" + isEmergency
8426                 + " isSatelliteEnabled:" + isSatelliteEnabled);
8427         if (!isAllowed && isSatelliteEnabled && !isEmergency) {
8428             // Disable P2P session if satellite is not allowed in current location
8429             disableSatelliteSession(isEmergency);
8430         }
8431     }
8432 
disableSatelliteSession(boolean isEmergency)8433     private void disableSatelliteSession(boolean isEmergency) {
8434         plogd("disableSatelliteSession: isEmergency=" + isEmergency);
8435         requestSatelliteEnabled(false /* enableSatellite */,
8436                 false /* enableDemoMode */, isEmergency,
8437                 new IIntegerConsumer.Stub() {
8438                     @Override
8439                     public void accept(int result) {
8440                         plogd("disableSatelliteSession:"
8441                                 + " requestSatelliteEnabled result=" + result);
8442                     }
8443                 });
8444     }
8445 
handleSatelliteAccessConfigUpdateResult( SatelliteAccessConfiguration satelliteAccessConfig)8446     private void handleSatelliteAccessConfigUpdateResult(
8447         SatelliteAccessConfiguration satelliteAccessConfig) {
8448         if(satelliteAccessConfig != null) {
8449             synchronized (mSatelliteAccessConfigLock) {
8450                 plogd("handleSatelliteAccessConfigUpdateResult:" + " satelliteAccessConfig="
8451                     + satelliteAccessConfig);
8452                 List<Integer> tagIds = satelliteAccessConfig.getTagIds();
8453                 if (!mCurrentLocationTagIds.equals(tagIds)) {
8454                     mCurrentLocationTagIds = tagIds;
8455                     sendMessageDelayed(obtainMessage(CMD_EVALUATE_ESOS_PROFILES_PRIORITIZATION),
8456                         mEvaluateEsosProfilesPrioritizationDurationMillis);
8457                 }
8458             }
8459         } else {
8460                 plogd("handleSatelliteAccessConfigUpdateResult: "
8461                     + "satelliteAccessConfiguration is null");
8462         }
8463     }
8464 
handleEventSatelliteRegistrationFailure(int causeCode)8465     private void handleEventSatelliteRegistrationFailure(int causeCode) {
8466         plogd("handleEventSatelliteRegistrationFailure: " + causeCode);
8467 
8468         List<ISatelliteModemStateCallback> deadCallersList = new ArrayList<>();
8469         mSatelliteRegistrationFailureListeners.values().forEach(listener -> {
8470             try {
8471                 listener.onRegistrationFailure(causeCode);
8472             } catch (RemoteException e) {
8473                 logd("handleEventSatelliteRegistrationFailure RemoteException: " + e);
8474                 deadCallersList.add(listener);
8475             }
8476         });
8477         deadCallersList.forEach(listener -> {
8478             mSatelliteRegistrationFailureListeners.remove(listener.asBinder());
8479         });
8480     }
8481 
handleEventTerrestrialNetworkAvailableChanged(boolean isAvailable)8482     private void handleEventTerrestrialNetworkAvailableChanged(boolean isAvailable) {
8483         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8484             plogd("handleEventTerrestrialNetworkAvailableChanged: "
8485                     + "carrierRoamingNbIotNtn flag is disabled");
8486             return;
8487         }
8488 
8489         plogd("handleEventTerrestrialNetworkAvailableChanged: " + isAvailable);
8490 
8491         List<ISatelliteModemStateCallback> deadCallersList = new ArrayList<>();
8492         mTerrestrialNetworkAvailableChangedListeners.values().forEach(listener -> {
8493             try {
8494                 listener.onTerrestrialNetworkAvailableChanged(isAvailable);
8495             } catch (RemoteException e) {
8496                 logd("handleEventTerrestrialNetworkAvailableChanged RemoteException: " + e);
8497                 deadCallersList.add(listener);
8498             }
8499         });
8500         deadCallersList.forEach(listener -> {
8501             mTerrestrialNetworkAvailableChangedListeners.remove(listener.asBinder());
8502         });
8503 
8504         if (isAvailable && !mIsEmergency) {
8505             requestSatelliteEnabled(
8506                     false /* enableSatellite */, false /* enableDemoMode */,
8507                     false /* isEmergency */,
8508                     new IIntegerConsumer.Stub() {
8509                         @Override
8510                         public void accept(int result) {
8511                             plogd("handleEventTerrestrialNetworkAvailableChanged:"
8512                                     + " requestSatelliteEnabled result=" + result);
8513                         }
8514                     });
8515         }
8516     }
8517 
8518     /**
8519      * This API can be used by only CTS to override the cached value for the device overlay config
8520      * value :
8521      * config_satellite_gateway_service_package and
8522      * config_satellite_carrier_roaming_esos_provisioned_class.
8523      * These values are set before sending an intent to broadcast there are any change to list of
8524      * subscriber informations.
8525      *
8526      * @param name the name is one of the following that constitute an intent.
8527      *             component package name, or component class name.
8528      * @return {@code true} if the setting is successful, {@code false} otherwise.
8529      */
setSatelliteSubscriberIdListChangedIntentComponent(String name)8530     public boolean setSatelliteSubscriberIdListChangedIntentComponent(String name) {
8531         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8532             logd("setSatelliteSubscriberIdListChangedIntentComponent: carrierRoamingNbIotNtn is "
8533                     + "disabled");
8534             return false;
8535         }
8536         if (!isMockModemAllowed()) {
8537             logd("setSatelliteSubscriberIdListChangedIntentComponent: mock modem is not allowed");
8538             return false;
8539         }
8540         logd("setSatelliteSubscriberIdListChangedIntentComponent:" + name);
8541 
8542         if (name.contains("/")) {
8543             mChangeIntentComponent = true;
8544         } else {
8545             mChangeIntentComponent = false;
8546             return true;
8547         }
8548         boolean result = true;
8549         String[] cmdPart = name.split("/");
8550         switch (cmdPart[0]) {
8551             case "-p": {
8552                 mConfigSatelliteGatewayServicePackage = cmdPart[1];
8553                 break;
8554             }
8555             case "-c": {
8556                 mConfigSatelliteCarrierRoamingEsosProvisionedClass = cmdPart[1];
8557                 break;
8558             }
8559             default:
8560                 logd("setSatelliteSubscriberIdListChangedIntentComponent: invalid name " + name);
8561                 result = false;
8562                 break;
8563         }
8564         return result;
8565     }
8566 
8567     /**
8568      * This API can be used by only CTS to override the satellite access allowed state for
8569      * a list of subscription IDs.
8570      *
8571      * @param subIdListStr The string representation of the list of subscription IDs,
8572      *                     which are numbers separated by comma.
8573      * @return {@code true} if the satellite access allowed state is set successfully,
8574      * {@code false} otherwise.
8575      */
setSatelliteAccessAllowedForSubscriptions(@ullable String subIdListStr)8576     public boolean setSatelliteAccessAllowedForSubscriptions(@Nullable String subIdListStr) {
8577         if (!isMockModemAllowed()) {
8578             plogd("setSatelliteAccessAllowedForSubscriptions: mock modem not allowed");
8579             return false;
8580         }
8581 
8582         plogd("setSatelliteAccessAllowedForSubscriptions: subIdListStr=" + subIdListStr);
8583         if (subIdListStr == null) {
8584             mCtsSatelliteAccessAllowedSubIds.clear();
8585             return true;
8586         }
8587 
8588         List<Integer> subIdList = new ArrayList<>();
8589         for (String subIdStr : subIdListStr.split(",")) {
8590             try {
8591                 subIdList.add(Integer.parseInt(subIdStr));
8592             } catch (NumberFormatException e) {
8593                 plogd("setSatelliteAccessAllowedForSubscriptions: invalid subIdStr=" + subIdStr);
8594                 return false;
8595             }
8596         }
8597         mCtsSatelliteAccessAllowedSubIds.clear();
8598         mCtsSatelliteAccessAllowedSubIds.addAll(subIdList);
8599         selectBindingSatelliteSubscription(false);
8600         return true;
8601     }
8602 
8603     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getConfigSatelliteGatewayServicePackage()8604     protected String getConfigSatelliteGatewayServicePackage() {
8605         if (!mChangeIntentComponent) {
8606             return getStringFromOverlayConfig(
8607                     R.string.config_satellite_gateway_service_package);
8608         }
8609         logd("getConfigSatelliteGatewayServicePackage: " + mConfigSatelliteGatewayServicePackage);
8610         return mConfigSatelliteGatewayServicePackage;
8611     }
8612 
getConfigSatelliteCarrierRoamingEsosProvisionedClass()8613     private String getConfigSatelliteCarrierRoamingEsosProvisionedClass() {
8614         if (!mChangeIntentComponent) {
8615             return getStringFromOverlayConfig(
8616                     R.string.config_satellite_carrier_roaming_esos_provisioned_class);
8617         }
8618         logd("getConfigSatelliteCarrierRoamingEsosProvisionedClass: "
8619                 + mConfigSatelliteCarrierRoamingEsosProvisionedClass);
8620         return mConfigSatelliteCarrierRoamingEsosProvisionedClass;
8621     }
8622 
registerDefaultSmsSubscriptionChangedBroadcastReceiver()8623     private void registerDefaultSmsSubscriptionChangedBroadcastReceiver() {
8624         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8625             plogd("registerDefaultSmsSubscriptionChangedBroadcastReceiver: Flag "
8626                     + "CarrierRoamingNbIotNtn is disabled");
8627             return;
8628         }
8629         IntentFilter intentFilter = new IntentFilter();
8630         intentFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
8631         mContext.registerReceiver(mDefaultSmsSubscriptionChangedBroadcastReceiver, intentFilter);
8632     }
8633 
8634     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getSupportedDeviceStates()8635     protected List<DeviceState> getSupportedDeviceStates() {
8636         return mContext.getSystemService(DeviceStateManager.class).getSupportedDeviceStates();
8637     }
8638 
getFeatureFlags()8639     FeatureFlags getFeatureFlags() {
8640         return mFeatureFlags;
8641     }
8642 
isSatelliteDisabled()8643     private boolean isSatelliteDisabled() {
8644         synchronized (mIsSatelliteEnabledLock) {
8645             return ((mIsSatelliteEnabled != null) && !mIsSatelliteEnabled);
8646         }
8647     }
8648 
shouldStopWaitForEnableResponseTimer( @onNull RequestSatelliteEnabledArgument argument)8649     private boolean shouldStopWaitForEnableResponseTimer(
8650             @NonNull RequestSatelliteEnabledArgument argument) {
8651         if (argument.enableSatellite) return true;
8652         synchronized (mSatelliteEnabledRequestLock) {
8653             return !mWaitingForSatelliteModemOff;
8654         }
8655     }
8656 
8657     /**
8658      * Method to override the Carrier roaming Non-terrestrial network eligibility check
8659      *
8660      * @param state         flag to enable or disable the Ntn eligibility check.
8661      * @param resetRequired reset overriding the check with adb command.
8662      */
overrideCarrierRoamingNtnEligibilityChanged(boolean state, boolean resetRequired)8663     public boolean overrideCarrierRoamingNtnEligibilityChanged(boolean state,
8664             boolean resetRequired) {
8665         Log.d(TAG, "overrideCarrierRoamingNtnEligibilityChanged state = " + state
8666                 + "  resetRequired = " + resetRequired);
8667         if (resetRequired) {
8668             mOverrideNtnEligibility = null;
8669         } else {
8670             if (mOverrideNtnEligibility == null) {
8671                 mOverrideNtnEligibility = new AtomicBoolean(state);
8672             } else {
8673                 mOverrideNtnEligibility.set(state);
8674             }
8675             synchronized (mSatellitePhoneLock) {
8676                 if (this.mSatellitePhone != null) {
8677                     updateLastNotifiedNtnEligibilityAndNotify(state);
8678                 }
8679             }
8680         }
8681         return true;
8682     }
8683 
8684     /**
8685      * This method check for the key KEY_SATELLITE_MAX_DATAGRAM_SIZE in carrier config. If
8686      * available it fetches the value and override the same in SatelliteCapabilities. Otherwise it
8687      * uses the value in the existed mSatelliteCapabilities.
8688      */
overrideSatelliteCapabilitiesIfApplicable()8689     private void overrideSatelliteCapabilitiesIfApplicable() {
8690         int subId = getSelectedSatelliteSubId();
8691         PersistableBundle config = getPersistableBundle(subId);
8692         if (config.containsKey(KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE_BYTES_INT)) {
8693             int datagramSize = config.getInt(KEY_SATELLITE_SOS_MAX_DATAGRAM_SIZE_BYTES_INT);
8694             SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId);
8695             if (!(subInfo == null || subInfo.isOnlyNonTerrestrialNetwork())) {
8696                 synchronized (mSatelliteCapabilitiesLock) {
8697                     this.mSatelliteCapabilities.setMaxBytesPerOutgoingDatagram(datagramSize);
8698                 }
8699             }
8700         }
8701     }
8702 
8703     /**
8704      * This method returns subscription id for supporting Ntn Only
8705      */
getNtnOnlySubscriptionId()8706     public int getNtnOnlySubscriptionId() {
8707         List<SubscriptionInfo> infoList = mSubscriptionManagerService.getAllSubInfoList(
8708                         mContext.getOpPackageName(), mContext.getAttributionTag());
8709         int subId = infoList.stream()
8710                 .filter(info -> info.isOnlyNonTerrestrialNetwork())
8711                 .mapToInt(SubscriptionInfo::getSubscriptionId)
8712                 .findFirst()
8713                 .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
8714         logd("getNtnOnlySubscriptionId: subId=" + subId);
8715         return subId;
8716     }
8717 
8718     @Nullable
getNtnOnlySatelliteSubscriberInfoList( Consumer<Integer> result)8719     private List<SatelliteSubscriberInfo> getNtnOnlySatelliteSubscriberInfoList(
8720             Consumer<Integer> result) {
8721         SatelliteSubscriberInfo satelliteSubscriberInfo = getNtnOnlySatelliteSubscriberInfo();
8722         if (satelliteSubscriberInfo == null) {
8723             result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
8724             return null;
8725         }
8726         List<SatelliteSubscriberInfo> satelliteSubscriberInfoList = new ArrayList<>();
8727         satelliteSubscriberInfoList.add(satelliteSubscriberInfo);
8728 
8729         return satelliteSubscriberInfoList;
8730     }
8731 
getNtnOnlySatelliteSubscriberInfo()8732     @Nullable private SatelliteSubscriberInfo getNtnOnlySatelliteSubscriberInfo() {
8733         int ntnOnlySubId = getNtnOnlySubscriptionId();
8734         if (ntnOnlySubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
8735             logw("getNtnOnlySatelliteSubscriberInfo: no ntn only subscription found");
8736             return null;
8737         }
8738         SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(ntnOnlySubId);
8739         if (subInfo == null) {
8740             logw("getNtnOnlySatelliteSubscriberInfo: no subscription info found for subId="
8741                     + ntnOnlySubId);
8742             return null;
8743         }
8744         return getSatelliteSubscriberInfo(subInfo);
8745     }
8746 
getSatelliteSubscriberInfo( @onNull SubscriptionInfo subInfo)8747     @Nullable private SatelliteSubscriberInfo getSatelliteSubscriberInfo(
8748         @NonNull SubscriptionInfo subInfo) {
8749         Pair<String, Integer> subscriberIdPair = getSubscriberIdAndType(subInfo);
8750         String subscriberId = subscriberIdPair.first;
8751         int carrierId = subInfo.getCarrierId();
8752         String apn = getConfigForSubId(subInfo.getSubscriptionId())
8753                 .getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
8754         logd("getSatelliteSubscriberInfo: subInfo: " + subInfo
8755                 + ", subscriberId:" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, subscriberId)
8756                 + " , carrierId=" + carrierId + " , apn=" + apn);
8757         if (subscriberId.isEmpty()) {
8758             logw("getSatelliteSubscriberInfo: not a satellite subscription.");
8759             return null;
8760         }
8761         return new SatelliteSubscriberInfo.Builder().setSubscriberId(subscriberId)
8762                         .setCarrierId(carrierId).setNiddApn(apn)
8763                         .setSubscriptionId(subInfo.getSubscriptionId())
8764                         .setSubscriberIdType(subscriberIdPair.second)
8765                         .build();
8766     }
8767 
8768     /**
8769      * The method will notify the change in the services update the
8770      * mEntitlementServiceTypeMapPerCarrier.
8771      *
8772      * @param subId              : SubscriptionId
8773      * @param plmnServiceTypeMap : entitlement service map.
8774      */
updateAndNotifyChangesInCarrierRoamingNtnAvailableServices(int subId, Map<String, List<Integer>> plmnServiceTypeMap)8775     private void updateAndNotifyChangesInCarrierRoamingNtnAvailableServices(int subId,
8776             Map<String, List<Integer>> plmnServiceTypeMap) {
8777         // If a service list is already cached, check it for changes
8778         int[] existingServices = getSupportedServicesOnCarrierRoamingNtn(subId);
8779         synchronized (mSupportedSatelliteServicesLock) {
8780             mEntitlementServiceTypeMapPerCarrier.put(subId, plmnServiceTypeMap);
8781         }
8782         int[] updatedServices = getSupportedServicesOnCarrierRoamingNtn(subId);
8783         if (existingServices.length > 0 && Arrays.equals(existingServices, updatedServices)) {
8784             plogd("No change in Entitlement service support data");
8785             return;
8786         }
8787         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
8788             updateLastNotifiedNtnAvailableServicesAndNotify(subId);
8789             evaluateCarrierRoamingNtnEligibilityChange();
8790         }
8791     }
8792 
handleCarrierRoamingNtnAvailableServicesChanged()8793     private void handleCarrierRoamingNtnAvailableServicesChanged() {
8794         int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
8795         if (activeSubIds == null) {
8796             plogd("handleCarrierRoamingNtnAvailableServicesChanged: activeSubIds is null.");
8797             return;
8798         }
8799 
8800         plogd("handleCarrierRoamingNtnAvailableServicesChanged: activeSubIds size="
8801                 + activeSubIds.length);
8802         for (int subId: activeSubIds) {
8803             handleCarrierRoamingNtnAvailableServicesChanged(subId);
8804         }
8805     }
8806 
8807     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
handleCarrierRoamingNtnAvailableServicesChanged(int subId)8808     protected void handleCarrierRoamingNtnAvailableServicesChanged(int subId) {
8809         plogd("handleCarrierRoamingNtnAvailableServicesChanged: subId=" + subId);
8810         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8811             plogd("handleCarrierRoamingNtnAvailableServicesChanged: "
8812                     + "carrierRoamingNbIotNtn flag is disabled");
8813             return;
8814         }
8815         updateLastNotifiedNtnAvailableServicesAndNotify(subId);
8816         evaluateCarrierRoamingNtnEligibilityChange();
8817     }
8818 
updateLastNotifiedNtnAvailableServicesAndNotify(int subId)8819     private void updateLastNotifiedNtnAvailableServicesAndNotify(int subId) {
8820         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
8821             plogd("notifyNtnAvailableServices: carrierRoamingNbIotNtn flag is disabled");
8822             return;
8823         }
8824         Phone phone = SatelliteServiceUtils.getPhone(subId);
8825         if (phone == null) {
8826             plogd("notifyNtnAvailableServices: phone is null.");
8827             return;
8828         }
8829         plogd("updateLastNotifiedNtnAvailableServicesAndNotify: phoneId= " + phone.getPhoneId());
8830         int[] services = getSupportedServicesOnCarrierRoamingNtn(subId);
8831         phone.notifyCarrierRoamingNtnAvailableServicesChanged(services);
8832     }
8833 
getAvailableServicesWithEntitlementForSubId(int subId)8834     private int[] getAvailableServicesWithEntitlementForSubId(int subId) {
8835         synchronized (mSupportedSatelliteServicesLock) {
8836             Map<String, List<Integer>> allowedServicesList =
8837                     mEntitlementServiceTypeMapPerCarrier.get(subId);
8838             if (allowedServicesList != null && !allowedServicesList.isEmpty()) {
8839                 Set<Integer> serviceTypes = new HashSet<>();
8840                 for (List<Integer> values : allowedServicesList.values()) {
8841                     serviceTypes.addAll(values);
8842                 }
8843 
8844                 int[] result = new int[serviceTypes.size()];
8845                 int i = 0;
8846                 for (int value : serviceTypes) {
8847                     result[i++] = value;
8848                 }
8849                 return result;
8850             } else {
8851                 return new int[0]; // Return an empty array if the map is null or empty
8852             }
8853         }
8854     }
8855 
8856     /**
8857      * Given a subscription ID, this returns the carriers' supported services on
8858      * non-terrestrial networks.
8859      *
8860      * @param subId Associated subscription ID.
8861      * return supported services at entitlement for the available carriers. Note: If available
8862      *        services/allowed service type field is empty at entitlement, information from
8863      *        {@link
8864      *        CarrierConfigManager#KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY}
8865      *        will be returned.
8866      */
getSupportedServicesOnCarrierRoamingNtn(int subId)8867     public int[] getSupportedServicesOnCarrierRoamingNtn(int subId) {
8868         if (isValidSubscriptionId(subId) && isSatelliteSupportedViaCarrier(subId)) {
8869             // check available services supported at entitlement for sub id
8870             int[] services = getAvailableServicesWithEntitlementForSubId(subId);
8871             logd("getAvailableServicesWithEntitlementForSubId: " + Arrays.toString(services));
8872             if (services.length == 0) {
8873                 services = getSupportedSatelliteServicesForCarrier(subId);
8874             }
8875             if (isP2PSmsDisallowedOnCarrierRoamingNtn(subId)) {
8876                 services = Arrays.stream(services).filter(
8877                         value -> value != NetworkRegistrationInfo.SERVICE_TYPE_SMS).toArray();
8878             }
8879             return services;
8880         }
8881         return new int[0];
8882     }
8883 
8884     /**
8885      * Whether the P2P SMS over carrier roaming satellite is disallowed or not.
8886      *
8887      * @param subId Associated subscription ID
8888      * return {@code true} when the phone does not support P2P SMS over carrier roaming satellite
8889      *        {@code false} otherwise
8890      */
isP2PSmsDisallowedOnCarrierRoamingNtn(int subId)8891     public boolean isP2PSmsDisallowedOnCarrierRoamingNtn(int subId) {
8892         int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
8893         if (carrierRoamingNtnConnectType == CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
8894             // Manual Connected
8895             plogd("isP2PSmsDisallowedOnCarrierRoamingNtn: manual connect");
8896             if (!isNtnSmsSupportedByMessagesApp()
8897                     || !isApplicationSupportsP2P(mSatelliteGatewayServicePackageName)) {
8898                 plogd("isP2PSmsDisallowedOnCarrierRoamingNtn: APKs do not supports P2P");
8899                 return true;
8900             }
8901         }
8902         plogd("isP2PSmsDisallowedOnCarrierRoamingNtn: P2P is supported");
8903         return false;
8904     }
8905 
8906     @NonNull
getSupportedSatelliteServicesForCarrier(int subId)8907     private int[] getSupportedSatelliteServicesForCarrier(int subId) {
8908         PersistableBundle config = getPersistableBundle(subId);
8909         int[] availableServices = config.getIntArray(
8910                 KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY);
8911         if (availableServices == null) {
8912             logd("getSupportedSatelliteServicesForCarrier: defaultCapabilities is null");
8913             return new int[0];
8914         }
8915         logd("getSupportedSatelliteServicesForCarrier: subId=" + subId
8916                 + ", return default values " + Arrays.toString(availableServices));
8917         return availableServices;
8918     }
8919 
8920     /**
8921      * Whether application supports the P2P SMS to connect to carrier roaming non-terrestrial
8922      * network.
8923      *
8924      * @param packageName application's default package name
8925      * return {@code true} when the application supports P2P SMS over the roaming satellite
8926      */
8927     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isApplicationSupportsP2P(String packageName)8928     public boolean isApplicationSupportsP2P(String packageName) {
8929         PackageManager pm = mContext.getPackageManager();
8930         ApplicationInfo applicationInfo = new ApplicationInfo();
8931         try {
8932             applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
8933         } catch (PackageManager.NameNotFoundException e) {
8934             logd("isApplicationSupportsP2P pkgName: " + packageName + " is not installed.");
8935             return false;
8936         }
8937         if (applicationInfo == null || applicationInfo.metaData == null) {
8938             logd("isApplicationSupportsP2P pkgName: " + packageName + " meta-data info is empty.");
8939             return false;
8940         }
8941         return applicationInfo.metaData.getBoolean(
8942                 SatelliteManager.METADATA_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT);
8943     }
8944 
8945     /**
8946      * Registers for the applications state changed.
8947      */
8948     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
registerApplicationStateChanged()8949     public void registerApplicationStateChanged() {
8950         mDefaultSmsPackageName = Telephony.Sms.getDefaultSmsPackage(mContext);
8951         mSatelliteGatewayServicePackageName = getConfigSatelliteGatewayServicePackage();
8952 
8953         IntentFilter packageFilter = new IntentFilter();
8954         packageFilter.addAction(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
8955         packageFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
8956         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
8957         packageFilter.addDataScheme("package");
8958         mContext.registerReceiver(mPackageStateChangedReceiver, packageFilter,
8959                 mContext.RECEIVER_EXPORTED);
8960     }
8961 
registerLocationServiceStateChanged()8962     private void registerLocationServiceStateChanged() {
8963         IntentFilter intentFilter = new IntentFilter();
8964         intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
8965         mContext.registerReceiver(mLocationServiceStateChangedReceiver, intentFilter);
8966     }
8967 
8968 
notifyEnabledStateChanged(boolean isEnabled)8969     private void notifyEnabledStateChanged(boolean isEnabled) {
8970         TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);
8971         if (trm == null) {
8972             loge("Telephony registry service is down!");
8973             return;
8974         }
8975 
8976         trm.notifySatelliteStateChanged(isEnabled);
8977         logd("notifyEnabledStateChanged to " + isEnabled);
8978     }
8979 
getCarrierRoamingNtnSignalStrength(@onNull Phone phone)8980     private NtnSignalStrength getCarrierRoamingNtnSignalStrength(@NonNull Phone phone) {
8981         NtnSignalStrength carrierRoamingNtnSignalStrength = new NtnSignalStrength(
8982                 NTN_SIGNAL_STRENGTH_NONE);
8983 
8984         if (isInCarrierRoamingNbIotNtn(phone)) {
8985             if (isInConnectedState()) {
8986                 synchronized (mNtnSignalsStrengthLock) {
8987                     carrierRoamingNtnSignalStrength = mNtnSignalStrength;
8988                 }
8989                 plogd("getCarrierRoamingNtnSignalStrength[phoneId=" + phone.getPhoneId()
8990                         + "]: in carrier roaming nb iot ntn mode.");
8991             }
8992         } else if (isInSatelliteModeForCarrierRoaming(phone)) {
8993             ServiceState serviceState = phone.getServiceState();
8994             if (serviceState.getState() != ServiceState.STATE_OUT_OF_SERVICE) {
8995                 carrierRoamingNtnSignalStrength = new NtnSignalStrength(
8996                         phone.getSignalStrength().getLevel());
8997                 plogd("getCarrierRoamingNtnSignalStrength[phoneId=" + phone.getPhoneId()
8998                         + "]: is in satellite mode for carrier roaming.");
8999             }
9000         }
9001 
9002         return carrierRoamingNtnSignalStrength;
9003     }
9004 
9005     /**
9006      * Returns satellite connected state from modem, return true if connected.
9007      */
isInConnectedState()9008     public boolean isInConnectedState() {
9009         synchronized (mSatelliteModemStateLock) {
9010             switch (mSatelliteModemState) {
9011                 case SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED: //fallthrough
9012                 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING: //fallthrough
9013                 case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING: //fallthrough
9014                 case SatelliteManager.SATELLITE_MODEM_STATE_IDLE:
9015                     plogd("isInConnectedState: return true");
9016                     return true;
9017                 default:
9018                     plogd("isInConnectedState: return false");
9019                     return false;
9020             }
9021         }
9022     }
9023 
updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify( @ullable Phone phone)9024     protected void updateLastNotifiedCarrierRoamingNtnSignalStrengthAndNotify(
9025             @Nullable Phone phone) {
9026         if (!mFeatureFlags.carrierRoamingNbIotNtn()) return;
9027         if (phone == null) {
9028             return;
9029         }
9030 
9031         NtnSignalStrength currSignalStrength = getCarrierRoamingNtnSignalStrength(phone);
9032         int subId = phone.getSubId();
9033         synchronized (mSatelliteConnectedLock) {
9034             NtnSignalStrength lastNotifiedSignalStrength =
9035                     mLastNotifiedCarrierRoamingNtnSignalStrength.get(subId);
9036             if (lastNotifiedSignalStrength == null
9037                     || lastNotifiedSignalStrength.getLevel() != currSignalStrength.getLevel()) {
9038                 mLastNotifiedCarrierRoamingNtnSignalStrength.put(subId, currSignalStrength);
9039                 phone.notifyCarrierRoamingNtnSignalStrengthChanged(currSignalStrength);
9040             }
9041         }
9042     }
9043 
9044     /** Returns whether to send SMS to DatagramDispatcher or not. */
shouldSendSmsToDatagramDispatcher(@ullable Phone phone)9045     public boolean shouldSendSmsToDatagramDispatcher(@Nullable Phone phone) {
9046         final long identity = Binder.clearCallingIdentity();
9047         try {
9048             if (!isInCarrierRoamingNbIotNtn(phone)) {
9049                 return false;
9050             }
9051 
9052             if (isDemoModeEnabled()) {
9053                 return false;
9054             }
9055 
9056             int[] services = getSupportedServicesOnCarrierRoamingNtn(phone.getSubId());
9057             return ArrayUtils.contains(services, NetworkRegistrationInfo.SERVICE_TYPE_SMS);
9058         } finally {
9059             Binder.restoreCallingIdentity(identity);
9060         }
9061     }
9062 
9063     /** Returns whether to drop SMS or not. */
shouldDropSms(@ullable Phone phone)9064     public boolean shouldDropSms(@Nullable Phone phone) {
9065         final long identity = Binder.clearCallingIdentity();
9066         try {
9067             if (!isInCarrierRoamingNbIotNtn(phone)) {
9068                 return false;
9069             }
9070 
9071             int[] services = getSupportedServicesOnCarrierRoamingNtn(phone.getSubId());
9072             return !ArrayUtils.contains(services, NetworkRegistrationInfo.SERVICE_TYPE_SMS);
9073         } finally {
9074             Binder.restoreCallingIdentity(identity);
9075         }
9076     }
9077 
isWaitingForSatelliteModemOff()9078     private boolean isWaitingForSatelliteModemOff() {
9079         synchronized (mSatelliteEnabledRequestLock) {
9080             return mWaitingForSatelliteModemOff;
9081         }
9082     }
9083 
9084     @Nullable
getIsSatelliteSupported()9085     private Boolean getIsSatelliteSupported() {
9086         synchronized (mIsSatelliteSupportedLock) {
9087             return mIsSatelliteSupported;
9088         }
9089     }
9090 
isWaitingForDisableSatelliteModemResponse()9091     private boolean isWaitingForDisableSatelliteModemResponse() {
9092         synchronized (mSatelliteEnabledRequestLock) {
9093             return mWaitingForDisableSatelliteModemResponse;
9094         }
9095     }
9096 
isSatelliteAccessAllowedAtCurrentLocation()9097     private boolean isSatelliteAccessAllowedAtCurrentLocation() {
9098         synchronized (mSatelliteAccessConfigLock) {
9099             return mSatelliteAccessAllowed;
9100         }
9101     }
9102 
9103     @Nullable
getIsSatelliteEnabled()9104     private Boolean getIsSatelliteEnabled() {
9105         synchronized (mIsSatelliteEnabledLock) {
9106             return mIsSatelliteEnabled;
9107         }
9108     }
9109 
9110     @Nullable
getSatelliteDisabledRequest()9111     private RequestSatelliteEnabledArgument getSatelliteDisabledRequest() {
9112         synchronized (mSatelliteEnabledRequestLock) {
9113             return mSatelliteDisabledRequest;
9114         }
9115     }
9116 
getSatelliteCapabilities()9117     private SatelliteCapabilities getSatelliteCapabilities() {
9118         synchronized (mSatelliteCapabilitiesLock) {
9119             return mSatelliteCapabilities;
9120         }
9121     }
9122 
setBTEnabledState(boolean enabled)9123     private void setBTEnabledState(boolean enabled) {
9124         synchronized (mRadioStateLock) {
9125             mBTStateEnabled = enabled;
9126         }
9127     }
9128 
getBTEnabledState()9129     private boolean getBTEnabledState() {
9130         synchronized (mRadioStateLock) {
9131             return mBTStateEnabled;
9132         }
9133     }
9134 
setNfcEnabledState(boolean enabled)9135     private void setNfcEnabledState(boolean enabled) {
9136         synchronized (mRadioStateLock) {
9137             mNfcStateEnabled = enabled;
9138         }
9139     }
9140 
getNfcEnabledState()9141     private boolean getNfcEnabledState() {
9142         synchronized (mRadioStateLock) {
9143             return mNfcStateEnabled;
9144         }
9145     }
9146 
setUwbEnabledState(boolean enabled)9147     private void setUwbEnabledState(boolean enabled) {
9148         synchronized (mRadioStateLock) {
9149             mUwbStateEnabled = enabled;
9150         }
9151     }
9152 
getUwbEnabledState()9153     private boolean getUwbEnabledState() {
9154         synchronized (mRadioStateLock) {
9155             return mUwbStateEnabled;
9156         }
9157     }
9158 
setWifiEnabledState(boolean enabled)9159     private void setWifiEnabledState(boolean enabled) {
9160         synchronized (mRadioStateLock) {
9161             mWifiStateEnabled = enabled;
9162         }
9163     }
9164 
getWifiEnabledState()9165     private boolean getWifiEnabledState() {
9166         synchronized (mRadioStateLock) {
9167             return mWifiStateEnabled;
9168         }
9169     }
9170 
9171     /**
9172      * Method to return the current data plan for the registered plmn based on entitlement
9173      * provisioning information. Note: If no information at
9174      * provisioning is supported this is overridden with operator carrier config information.
9175      *
9176      * @param subId current subscription id
9177      * @param plmn current registered plmn information
9178      *
9179      * @return Data supported modes {@link SatelliteController#SATELLITE_DATA_PLAN_METERED}
9180      */
getSatelliteDataPlanForPlmn(int subId, String plmn)9181     public int getSatelliteDataPlanForPlmn(int subId, String plmn) {
9182         if (plmn != null) {
9183             synchronized (mSupportedSatelliteServicesLock) {
9184                 Map<String, Integer> dataplanMap = mEntitlementDataPlanMapPerCarrier.get(subId);
9185                 logd("data plan available for sub id:" + dataplanMap);
9186                 if (dataplanMap != null && dataplanMap.containsKey(plmn)) {
9187                     return dataplanMap.get(plmn);
9188                 }
9189             }
9190         }
9191         // TODO (Override with carrier config value when configuration defined)
9192         return SATELLITE_DATA_PLAN_METERED;
9193     }
9194 
9195     /**
9196      * Check if the available satellite services support
9197      * {@link NetworkRegistrationInfo#SERVICE_TYPE_DATA} service or not.
9198      *
9199      * @return {@code true} if data services is supported, otherwise {@code false}.
9200      */
isSatelliteDataServicesAllowed(int subId, String plmn)9201     private boolean isSatelliteDataServicesAllowed(int subId, String plmn) {
9202         // validate is available services support data, for satellite internet bringup
9203         List<Integer> availableServices = getSupportedSatelliteServicesForPlmn(subId, plmn);
9204         return availableServices.stream().anyMatch(num -> num
9205                 == NetworkRegistrationInfo.SERVICE_TYPE_DATA);
9206     }
9207 
9208     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
isLocationServiceEnabled()9209     protected boolean isLocationServiceEnabled() {
9210         LocationManager lm = mContext.createAttributionContext("telephony")
9211                 .getSystemService(LocationManager.class);
9212         if (lm != null) {
9213             return lm.isLocationEnabled();
9214         }
9215 
9216         return true;
9217     }
9218 
9219     /**
9220      * Method to return the current satellite data service policy supported mode for the registered
9221      * plmn based on entitlement provisioning information. Note: If no information at
9222      * provisioning is supported this is overridden with operator carrier config information
9223      * if available satellite services support data else data service policy is marked as
9224      * restricted.
9225      *
9226      * @param subId current subscription id
9227      * @param plmn current registered plmn information
9228      *
9229      * @return Supported modes {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}
9230      */
getSatelliteDataServicePolicyForPlmn(int subId, String plmn)9231     public int getSatelliteDataServicePolicyForPlmn(int subId, String plmn) {
9232         plogd("getSatelliteDataServicePolicyForPlmn: subId=" + subId + " plmn=" + plmn);
9233         if (isValidSubscriptionId(subId)) {
9234             Map<String, Integer> dataServicePolicy;
9235             synchronized (mSupportedSatelliteServicesLock) {
9236                 dataServicePolicy = mEntitlementDataServicePolicyMapPerCarrier.get(subId);
9237             }
9238             plogd("getSatelliteDataServicePolicyForPlmn: dataServicePolicy=" + dataServicePolicy);
9239 
9240             if (dataServicePolicy != null) {
9241                 if (!TextUtils.isEmpty(plmn) && dataServicePolicy.containsKey(plmn)) {
9242                     plogd("getSatelliteDataServicePolicyForPlmn: "
9243                             + "return policy using dataServicePolicy map");
9244                     return dataServicePolicy.get(plmn);
9245                 } else if (TextUtils.isEmpty(plmn)) {
9246                     int preferredPolicy =
9247                             CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED;
9248                     for (String plmnKey : dataServicePolicy.keySet()) {
9249                         int policy = dataServicePolicy.get(plmnKey);
9250                         // higher value has higher preference
9251                         if (policy > preferredPolicy) {
9252                             preferredPolicy = policy;
9253                         }
9254                     }
9255                     plogd("getSatelliteDataServicePolicyForPlmn: "
9256                             + "return preferredPolicy=" + preferredPolicy);
9257                     return preferredPolicy;
9258                 }
9259             }
9260 
9261             if (isSatelliteDataServicesAllowed(subId, plmn)) {
9262                 plogd("getSatelliteDataServicePolicyForPlmn: return data support mode from config");
9263                 return getCarrierSatelliteDataSupportedModeFromConfig(subId);
9264             }
9265         }
9266 
9267         plogd("getSatelliteDataServicePolicyForPlmn: return data support only restricted");
9268         return CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED;
9269     }
9270 
9271     /**
9272      * Method to return the current satellite voice service policy supported mode for the registered
9273      * plmn based on entitlement provisioning information. Note: If no information at
9274      * provisioning is supported this is overridden with operator carrier config information.
9275      *
9276      * @param subId current subscription id
9277      * @param plmn current registered plmn information
9278      *
9279      * @return Supported modes {@link CarrierConfigManager.SATELLITE_DATA_SUPPORT_MODE}
9280      */
getSatelliteVoiceServicePolicyForPlmn(int subId, String plmn)9281     public int getSatelliteVoiceServicePolicyForPlmn(int subId, String plmn) {
9282         if (plmn != null) {
9283             synchronized (mSupportedSatelliteServicesLock) {
9284                 Map<String, Integer> voiceServicePolicy =
9285                         mEntitlementVoiceServicePolicyMapPerCarrier.get(
9286                                 subId);
9287                 logd("voice policy available for sub id:" + voiceServicePolicy);
9288                 if (voiceServicePolicy != null && voiceServicePolicy.containsKey(plmn)
9289                         && !plmn.isEmpty()) {
9290                     return voiceServicePolicy.get(plmn);
9291                 }
9292             }
9293         }
9294         // TODO (Replace below code with related enum value, when voice service policy support mode
9295         // is added)
9296         return 0; // Restricted
9297     }
9298 
9299     /**
9300      * Get list of applications that are optimized for low bandwidth satellite data.
9301      *
9302      * @param userId is Identifier of user
9303      *
9304      * @return List of Application Name with data optimized network property.
9305      * {@link #PROPERTY_SATELLITE_DATA_OPTIMIZED}
9306      */
getSatelliteDataOptimizedApps(int userId)9307     public List<String> getSatelliteDataOptimizedApps(int userId) {
9308         if (mFeatureFlags.carrierRoamingNbIotNtn()) {
9309             return mSatelliteOptimizedApplicationsTracker.getSatelliteOptimizedApplications(userId);
9310         } else {
9311             return new ArrayList<>();
9312         }
9313     }
9314 
9315     /**
9316      * Method to return the current satellite data service policy supported mode for the
9317      * subscription id based on carrier config.
9318      *
9319      * @param subId current subscription id.
9320      *
9321      * @return Supported modes {@link SatelliteManager#SatelliteDataSupportMode}
9322      *
9323      * @hide
9324      */
9325     @SatelliteManager.SatelliteDataSupportMode
getSatelliteDataSupportMode(int subId)9326     public int getSatelliteDataSupportMode(int subId) {
9327         if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
9328             return SatelliteManager.SATELLITE_DATA_SUPPORT_RESTRICTED;
9329         }
9330 
9331         return getSatelliteDataServicePolicyForPlmn(subId, "");
9332     }
9333 
9334     /**
9335      * This API can be used by only CTS to make the function {@link #getAllPlmnSet()} to exclude the
9336      * PLMN list from storage from the returned result.
9337      *
9338      * @param enabled Whether to enable boolean config.
9339      * @return {@code true} if the value is set successfully, {@code false} otherwise.
9340      */
setSatelliteIgnorePlmnListFromStorage(boolean enabled)9341     public boolean setSatelliteIgnorePlmnListFromStorage(boolean enabled) {
9342         plogd("setSatelliteIgnorePlmnListFromStorage - " + enabled);
9343         mIgnorePlmnListFromStorage.set(enabled);
9344         return true;
9345     }
9346 }
9347