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.provider.Settings.ACTION_SATELLITE_SETTING;
20 import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY;
21 import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
22 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
23 import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL;
24 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
25 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
26 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
27 import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
28 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
29 import static android.telephony.SubscriptionManager.isValidSubscriptionId;
30 import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
31 import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
32 import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
33 import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
34 import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT;
35 import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
36 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
37 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
38 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
39 
40 import static com.android.internal.telephony.configupdate.ConfigProviderAdaptor.DOMAIN_SATELLITE;
41 
42 import android.annotation.ArrayRes;
43 import android.annotation.NonNull;
44 import android.annotation.Nullable;
45 import android.app.Notification;
46 import android.app.NotificationChannel;
47 import android.app.NotificationManager;
48 import android.app.PendingIntent;
49 import android.bluetooth.BluetoothAdapter;
50 import android.content.BroadcastReceiver;
51 import android.content.ContentResolver;
52 import android.content.Context;
53 import android.content.Intent;
54 import android.content.IntentFilter;
55 import android.content.SharedPreferences;
56 import android.content.pm.PackageManager;
57 import android.content.res.Resources;
58 import android.database.ContentObserver;
59 import android.net.Uri;
60 import android.net.wifi.WifiManager;
61 import android.nfc.NfcAdapter;
62 import android.os.AsyncResult;
63 import android.os.Binder;
64 import android.os.Build;
65 import android.os.Bundle;
66 import android.os.CancellationSignal;
67 import android.os.Handler;
68 import android.os.HandlerExecutor;
69 import android.os.HandlerThread;
70 import android.os.IBinder;
71 import android.os.ICancellationSignal;
72 import android.os.Looper;
73 import android.os.Message;
74 import android.os.PersistableBundle;
75 import android.os.Registrant;
76 import android.os.RegistrantList;
77 import android.os.RemoteException;
78 import android.os.ResultReceiver;
79 import android.os.ServiceSpecificException;
80 import android.os.SystemClock;
81 import android.os.SystemProperties;
82 import android.os.UserHandle;
83 import android.provider.Settings;
84 import android.provider.Telephony;
85 import android.telephony.AccessNetworkConstants;
86 import android.telephony.CarrierConfigManager;
87 import android.telephony.DropBoxManagerLoggerBackend;
88 import android.telephony.NetworkRegistrationInfo;
89 import android.telephony.PersistentLogger;
90 import android.telephony.Rlog;
91 import android.telephony.ServiceState;
92 import android.telephony.SubscriptionManager;
93 import android.telephony.TelephonyManager;
94 import android.telephony.satellite.INtnSignalStrengthCallback;
95 import android.telephony.satellite.ISatelliteCapabilitiesCallback;
96 import android.telephony.satellite.ISatelliteDatagramCallback;
97 import android.telephony.satellite.ISatelliteModemStateCallback;
98 import android.telephony.satellite.ISatelliteProvisionStateCallback;
99 import android.telephony.satellite.ISatelliteSupportedStateCallback;
100 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
101 import android.telephony.satellite.NtnSignalStrength;
102 import android.telephony.satellite.SatelliteCapabilities;
103 import android.telephony.satellite.SatelliteDatagram;
104 import android.telephony.satellite.SatelliteManager;
105 import android.util.Log;
106 import android.util.Pair;
107 import android.util.SparseArray;
108 import android.util.SparseBooleanArray;
109 import android.uwb.UwbManager;
110 
111 import com.android.internal.R;
112 import com.android.internal.annotations.GuardedBy;
113 import com.android.internal.annotations.VisibleForTesting;
114 import com.android.internal.telephony.CommandsInterface;
115 import com.android.internal.telephony.DeviceStateMonitor;
116 import com.android.internal.telephony.IIntegerConsumer;
117 import com.android.internal.telephony.Phone;
118 import com.android.internal.telephony.PhoneFactory;
119 import com.android.internal.telephony.configupdate.ConfigParser;
120 import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
121 import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
122 import com.android.internal.telephony.flags.FeatureFlags;
123 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteControllerStats;
124 import com.android.internal.telephony.satellite.metrics.CarrierRoamingSatelliteSessionStats;
125 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
126 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
127 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
128 import com.android.internal.telephony.subscription.SubscriptionManagerService;
129 import com.android.internal.telephony.util.TelephonyUtils;
130 import com.android.internal.util.FunctionalUtils;
131 
132 import java.util.ArrayList;
133 import java.util.Arrays;
134 import java.util.Collections;
135 import java.util.HashMap;
136 import java.util.HashSet;
137 import java.util.List;
138 import java.util.Map;
139 import java.util.Optional;
140 import java.util.Set;
141 import java.util.concurrent.ConcurrentHashMap;
142 import java.util.concurrent.Executors;
143 import java.util.concurrent.TimeUnit;
144 import java.util.concurrent.atomic.AtomicBoolean;
145 import java.util.concurrent.atomic.AtomicLong;
146 import java.util.function.Consumer;
147 import java.util.stream.Collectors;
148 
149 /**
150  * Satellite controller is the backend service of
151  * {@link android.telephony.satellite.SatelliteManager}.
152  */
153 public class SatelliteController extends Handler {
154     private static final String TAG = "SatelliteController";
155     /** Whether enabling verbose debugging message or not. */
156     private static final boolean DBG = false;
157     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
158     private static final boolean DEBUG = !"user".equals(Build.TYPE);
159     /** File used to store shared preferences related to satellite. */
160     public static final String SATELLITE_SHARED_PREF = "satellite_shared_pref";
161     public static final String SATELLITE_SUBSCRIPTION_ID = "satellite_subscription_id";
162     /** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */
163     public static final int SATELLITE_MODE_ENABLED_TRUE = 1;
164     public static final int SATELLITE_MODE_ENABLED_FALSE = 0;
165     public static final int INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE = -1;
166     /**
167      * This is used by CTS to override the timeout duration to wait for the response of the request
168      * to enable satellite.
169      */
170     public static final int TIMEOUT_TYPE_WAIT_FOR_SATELLITE_ENABLING_RESPONSE = 1;
171     /** This is used by CTS to override demo pointing aligned duration. */
172     public static final int TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS = 2;
173     /** This is used by CTS to override demo pointing not aligned duration. */
174     public static final int TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS = 3;
175 
176     /** Key used to read/write OEM-enabled satellite provision status in shared preferences. */
177     private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY =
178             "oem_enabled_satellite_provision_status_key";
179 
180     public static final long DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS =
181             TimeUnit.SECONDS.toMillis(30);
182 
183     /** Message codes used in handleMessage() */
184     //TODO: Move the Commands and events related to position updates to PointingAppController
185     private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1;
186     private static final int EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE = 2;
187     private static final int CMD_STOP_SATELLITE_TRANSMISSION_UPDATES = 3;
188     private static final int EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE = 4;
189     private static final int CMD_PROVISION_SATELLITE_SERVICE = 7;
190     private static final int EVENT_PROVISION_SATELLITE_SERVICE_DONE = 8;
191     private static final int CMD_DEPROVISION_SATELLITE_SERVICE = 9;
192     private static final int EVENT_DEPROVISION_SATELLITE_SERVICE_DONE = 10;
193     private static final int CMD_SET_SATELLITE_ENABLED = 11;
194     private static final int EVENT_SET_SATELLITE_ENABLED_DONE = 12;
195     private static final int CMD_IS_SATELLITE_ENABLED = 13;
196     private static final int EVENT_IS_SATELLITE_ENABLED_DONE = 14;
197     private static final int CMD_IS_SATELLITE_SUPPORTED = 15;
198     private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16;
199     private static final int CMD_GET_SATELLITE_CAPABILITIES = 17;
200     private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18;
201     private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21;
202     private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22;
203     private static final int EVENT_RADIO_STATE_CHANGED = 23;
204     private static final int CMD_IS_SATELLITE_PROVISIONED = 24;
205     private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25;
206     private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26;
207     private static final int EVENT_PENDING_DATAGRAMS = 27;
208     private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28;
209     private static final int EVENT_SET_SATELLITE_PLMN_INFO_DONE = 29;
210     private static final int CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE = 30;
211     private static final int EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE = 31;
212     private static final int CMD_REQUEST_NTN_SIGNAL_STRENGTH = 32;
213     private static final int EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE = 33;
214     private static final int EVENT_NTN_SIGNAL_STRENGTH_CHANGED = 34;
215     private static final int CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING = 35;
216     private static final int EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE = 36;
217     private static final int EVENT_SERVICE_STATE_CHANGED = 37;
218     private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38;
219     private static final int EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT = 39;
220     private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
221     private static final int EVENT_SATELLITE_SUPPORTED_STATE_CHANGED = 41;
222     private static final int EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT = 42;
223 
224     @NonNull private static SatelliteController sInstance;
225     @NonNull private final Context mContext;
226     @NonNull private final SatelliteModemInterface mSatelliteModemInterface;
227     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
228     @NonNull protected SatelliteSessionController mSatelliteSessionController;
229     @NonNull private final PointingAppController mPointingAppController;
230     @NonNull private final DatagramController mDatagramController;
231     @NonNull private final ControllerMetricsStats mControllerMetricsStats;
232     @NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
233     @NonNull private SessionMetricsStats mSessionMetricsStats;
234     @NonNull private CarrierRoamingSatelliteControllerStats mCarrierRoamingSatelliteControllerStats;
235     @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
236     private final CommandsInterface mCi;
237     private ContentResolver mContentResolver;
238     private final DeviceStateMonitor mDSM;
239 
240     private final Object mRadioStateLock = new Object();
241 
242     /** Flags to indicate whether the respective radio is enabled */
243     @GuardedBy("mRadioStateLock")
244     private boolean mBTStateEnabled = false;
245     @GuardedBy("mRadioStateLock")
246     private boolean mNfcStateEnabled = false;
247     @GuardedBy("mRadioStateLock")
248     private boolean mUwbStateEnabled = false;
249     @GuardedBy("mRadioStateLock")
250     private boolean mWifiStateEnabled = false;
251 
252     // Flags to indicate that respective radios need to be disabled when satellite is enabled
253     private boolean mDisableBTOnSatelliteEnabled = false;
254     private boolean mDisableNFCOnSatelliteEnabled = false;
255     private boolean mDisableUWBOnSatelliteEnabled = false;
256     private boolean mDisableWifiOnSatelliteEnabled = false;
257 
258     private final Object mSatelliteEnabledRequestLock = new Object();
259     @GuardedBy("mSatelliteEnabledRequestLock")
260     private RequestSatelliteEnabledArgument mSatelliteEnabledRequest = null;
261     /** Flag to indicate that satellite is enabled successfully
262      * and waiting for all the radios to be disabled so that success can be sent to callback
263      */
264     @GuardedBy("mSatelliteEnabledRequestLock")
265     private boolean mWaitingForRadioDisabled = false;
266 
267     private boolean mWaitingForDisableSatelliteModemResponse = false;
268     private boolean mWaitingForSatelliteModemOff = false;
269 
270     private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService =
271             new AtomicBoolean(false);
272     private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService =
273             new AtomicBoolean(false);
274     private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService =
275             new AtomicBoolean(false);
276     private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false);
277     private final AtomicBoolean mRegisteredForSatelliteCapabilitiesChanged =
278             new AtomicBoolean(false);
279     private final AtomicBoolean mIsModemEnabledReportingNtnSignalStrength =
280             new AtomicBoolean(false);
281     private final AtomicBoolean mLatestRequestedStateForNtnSignalStrengthReport =
282             new AtomicBoolean(false);
283     private final AtomicBoolean mRegisteredForSatelliteSupportedStateChanged =
284             new AtomicBoolean(false);
285     /**
286      * Map key: subId, value: callback to get error code of the provision request.
287      */
288     private final ConcurrentHashMap<Integer, Consumer<Integer>> mSatelliteProvisionCallbacks =
289             new ConcurrentHashMap<>();
290 
291     /**
292      * Map key: binder of the callback, value: callback to receive provision state changed events.
293      */
294     private final ConcurrentHashMap<IBinder, ISatelliteProvisionStateCallback>
295             mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>();
296     /**
297      * Map key: binder of the callback, value: callback to receive non-terrestrial signal strength
298      * state changed events.
299      */
300     private final ConcurrentHashMap<IBinder, INtnSignalStrengthCallback>
301             mNtnSignalStrengthChangedListeners = new ConcurrentHashMap<>();
302     /**
303      * Map key: binder of the callback, value: callback to receive satellite capabilities changed
304      * events.
305      */
306     private final ConcurrentHashMap<IBinder, ISatelliteCapabilitiesCallback>
307             mSatelliteCapabilitiesChangedListeners = new ConcurrentHashMap<>();
308     /**
309      * Map key: binder of the callback, value: callback to receive supported state changed events.
310      */
311     private final ConcurrentHashMap<IBinder, ISatelliteSupportedStateCallback>
312             mSatelliteSupportedStateChangedListeners = new ConcurrentHashMap<>();
313     private final Object mIsSatelliteSupportedLock = new Object();
314     @GuardedBy("mIsSatelliteSupportedLock")
315     private Boolean mIsSatelliteSupported = null;
316     private boolean mIsDemoModeEnabled = false;
317     private boolean mIsEmergency = false;
318     private final Object mIsSatelliteEnabledLock = new Object();
319     @GuardedBy("mIsSatelliteEnabledLock")
320     private Boolean mIsSatelliteEnabled = null;
321     private final Object mIsRadioOnLock = new Object();
322     @GuardedBy("mIsRadioOnLock")
323     private boolean mIsRadioOn = false;
324     private final Object mSatelliteViaOemProvisionLock = new Object();
325     @GuardedBy("mSatelliteViaOemProvisionLock")
326     private Boolean mIsSatelliteViaOemProvisioned = null;
327     @GuardedBy("mSatelliteViaOemProvisionLock")
328     private Boolean mOverriddenIsSatelliteViaOemProvisioned = null;
329     private final Object mSatelliteCapabilitiesLock = new Object();
330     @GuardedBy("mSatelliteCapabilitiesLock")
331     private SatelliteCapabilities mSatelliteCapabilities;
332     private final Object mNeedsSatellitePointingLock = new Object();
333     @GuardedBy("mNeedsSatellitePointingLock")
334     private boolean mNeedsSatellitePointing = false;
335     private final Object mNtnSignalsStrengthLock = new Object();
336     @GuardedBy("mNtnSignalsStrengthLock")
337     private NtnSignalStrength mNtnSignalStrength =
338             new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
339     /** Key: subId, value: (key: PLMN, value: set of
340      * {@link android.telephony.NetworkRegistrationInfo.ServiceType})
341      */
342     @GuardedBy("mSupportedSatelliteServicesLock")
343     @NonNull private final Map<Integer, Map<String, Set<Integer>>>
344             mSatelliteServicesSupportedByCarriers = new HashMap<>();
345     @NonNull private final Object mSupportedSatelliteServicesLock = new Object();
346     @NonNull private final List<String> mSatellitePlmnListFromOverlayConfig;
347     @NonNull private final CarrierConfigManager mCarrierConfigManager;
348     @NonNull private final CarrierConfigManager.CarrierConfigChangeListener
349             mCarrierConfigChangeListener;
350     @NonNull private final ConfigProviderAdaptor.Callback mConfigDataUpdatedCallback;
351     @NonNull private final Object mCarrierConfigArrayLock = new Object();
352     @GuardedBy("mCarrierConfigArrayLock")
353     @NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>();
354     @GuardedBy("mIsSatelliteEnabledLock")
355     /** Key: Subscription ID, value: set of restriction reasons for satellite communication.*/
356     @NonNull private final Map<Integer, Set<Integer>> mSatelliteAttachRestrictionForCarrierArray =
357             new HashMap<>();
358     @GuardedBy("mIsSatelliteEnabledLock")
359     /** Key: Subscription ID, value: the actual satellite enabled state in the modem -
360      * {@code true} for enabled and {@code false} for disabled. */
361     @NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub =
362             new HashMap<>();
363     @NonNull private final FeatureFlags mFeatureFlags;
364     @NonNull private final Object mSatelliteConnectedLock = new Object();
365     /** Key: Subscription ID; Value: Last satellite connected time */
366     @GuardedBy("mSatelliteConnectedLock")
367     @NonNull private final SparseArray<Long> mLastSatelliteDisconnectedTimesMillis =
368             new SparseArray<>();
369     /**
370      * Key: Subscription ID; Value: {@code true} if satellite was just connected,
371      * {@code false} otherwise.
372      */
373     @GuardedBy("mSatelliteConnectedLock")
374     @NonNull private final SparseBooleanArray
375             mWasSatelliteConnectedViaCarrier = new SparseBooleanArray();
376 
377     @GuardedBy("mSatelliteConnectedLock")
378     @NonNull private final SparseBooleanArray mLastNotifiedNtnMode = new SparseBooleanArray();
379 
380     @GuardedBy("mSatelliteConnectedLock")
381     @NonNull private final SparseBooleanArray mInitialized = new SparseBooleanArray();
382 
383     @GuardedBy("mSatelliteConnectedLock")
384     @NonNull private final Map<Integer, CarrierRoamingSatelliteSessionStats>
385             mCarrierRoamingSatelliteSessionStatsMap = new HashMap<>();
386 
387     /**
388      * Key: Subscription ID; Value: set of
389      * {@link android.telephony.NetworkRegistrationInfo.ServiceType}
390      */
391     @GuardedBy("mSatelliteConnectedLock")
392     @NonNull private final Map<Integer, List<Integer>>
393             mSatModeCapabilitiesForCarrierRoaming = new HashMap<>();
394 
395     /**
396      * This is used for testing only. When mEnforcedEmergencyCallToSatelliteHandoverType is valid,
397      * Telephony will ignore the IMS registration status and cellular availability, and always send
398      * the connection event EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
399      */
400     private int mEnforcedEmergencyCallToSatelliteHandoverType =
401             INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
402     private int mDelayInSendingEventDisplayEmergencyMessage = 0;
403     @NonNull private SharedPreferences mSharedPreferences = null;
404 
405     @Nullable private PersistentLogger mPersistentLogger = null;
406 
407     /**
408      * Key : Subscription ID, Value: {@code true} if the EntitlementStatus is enabled,
409      * {@code false} otherwise.
410      */
411     @GuardedBy("mSupportedSatelliteServicesLock")
412     private SparseBooleanArray mSatelliteEntitlementStatusPerCarrier = new SparseBooleanArray();
413     /** Key Subscription ID, value : PLMN allowed list from entitlement. */
414     @GuardedBy("mSupportedSatelliteServicesLock")
415     private SparseArray<List<String>> mEntitlementPlmnListPerCarrier = new SparseArray<>();
416     /** Key Subscription ID, value : PLMN barred list from entitlement. */
417     @GuardedBy("mSupportedSatelliteServicesLock")
418     private SparseArray<List<String>> mEntitlementBarredPlmnListPerCarrier = new SparseArray<>();
419     /**
420      * Key : Subscription ID, Value : If there is an entitlementPlmnList, use it. Otherwise, use the
421      * carrierPlmnList. */
422     @GuardedBy("mSupportedSatelliteServicesLock")
423     private final SparseArray<List<String>> mMergedPlmnListPerCarrier = new SparseArray<>();
424     private static AtomicLong sNextSatelliteEnableRequestId = new AtomicLong(0);
425     private long mWaitTimeForSatelliteEnablingResponse;
426     private long mDemoPointingAlignedDurationMillis;
427     private long mDemoPointingNotAlignedDurationMillis;
428     private final Object mLock = new Object();
429     @GuardedBy("mLock")
430     private long mLastEmergencyCallTime;
431     private long mSatelliteEmergencyModeDurationMillis;
432     private static final int DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS = 300;
433 
434     /** Key used to read/write satellite system notification done in shared preferences. */
435     private static final String SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY =
436             "satellite_system_notification_done_key";
437     // The notification tag used when showing a notification. The combination of notification tag
438     // and notification id should be unique within the phone app.
439     private static final String NOTIFICATION_TAG = "SatelliteController";
440     private static final int NOTIFICATION_ID = 1;
441     private static final String NOTIFICATION_CHANNEL = "satelliteChannel";
442     private static final String NOTIFICATION_CHANNEL_ID = "satellite";
443 
444     private final RegistrantList mSatelliteConfigUpdateChangedRegistrants = new RegistrantList();
445     private final BTWifiNFCStateReceiver mBTWifiNFCSateReceiver;
446     private final UwbAdapterStateCallback mUwbAdapterStateCallback;
447 
448     private long mSessionStartTimeStamp;
449     private long mSessionProcessingTimeStamp;
450 
451     // Variable for backup and restore device's screen rotation settings.
452     private String mDeviceRotationLockToBackupAndRestore = null;
453 
454     /**
455      * @return The singleton instance of SatelliteController.
456      */
getInstance()457     public static SatelliteController getInstance() {
458         if (sInstance == null) {
459             loge("SatelliteController was not yet initialized.");
460         }
461         return sInstance;
462     }
463 
464     /**
465      * Create the SatelliteController singleton instance.
466      * @param context The Context to use to create the SatelliteController.
467      * @param featureFlags The feature flag.
468      */
make(@onNull Context context, @NonNull FeatureFlags featureFlags)469     public static void make(@NonNull Context context, @NonNull FeatureFlags featureFlags) {
470         if (sInstance == null) {
471             HandlerThread satelliteThread = new HandlerThread(TAG);
472             satelliteThread.start();
473             sInstance = new SatelliteController(context, satelliteThread.getLooper(), featureFlags);
474         }
475     }
476 
477     /**
478      * Create a SatelliteController to act as a backend service of
479      * {@link android.telephony.satellite.SatelliteManager}
480      *
481      * @param context The Context for the SatelliteController.
482      * @param looper The looper for the handler. It does not run on main thread.
483      * @param featureFlags The feature flag.
484      */
485     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
SatelliteController( @onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags)486     public SatelliteController(
487             @NonNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags) {
488         super(looper);
489 
490         if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
491             mPersistentLogger = new PersistentLogger(
492                     DropBoxManagerLoggerBackend.getInstance(context));
493         }
494 
495         mContext = context;
496         mFeatureFlags = featureFlags;
497         Phone phone = SatelliteServiceUtils.getPhone();
498         mCi = phone.mCi;
499         mDSM = phone.getDeviceStateMonitor();
500         // Create the SatelliteModemInterface singleton, which is used to manage connections
501         // to the satellite service and HAL interface.
502         mSatelliteModemInterface = SatelliteModemInterface.make(
503                 mContext, this, mFeatureFlags);
504 
505         // Create the PointingUIController singleton,
506         // which is used to manage interactions with PointingUI app.
507         mPointingAppController = PointingAppController.make(mContext, mFeatureFlags);
508 
509         // Create the SatelliteControllerMetrics to report controller metrics
510         // should be called before making DatagramController
511         mControllerMetricsStats = ControllerMetricsStats.make(mContext);
512         mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance();
513         mSessionMetricsStats = SessionMetricsStats.getInstance();
514         mCarrierRoamingSatelliteControllerStats =
515                 CarrierRoamingSatelliteControllerStats.getOrCreateInstance();
516         mSubscriptionManagerService = SubscriptionManagerService.getInstance();
517 
518         // Create the DatagramController singleton,
519         // which is used to send and receive satellite datagrams.
520         mDatagramController = DatagramController.make(
521                 mContext, looper, mFeatureFlags, mPointingAppController);
522 
523         mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
524         synchronized (mIsRadioOnLock) {
525             mIsRadioOn = phone.isRadioOn();
526         }
527 
528         registerForSatelliteProvisionStateChanged();
529         registerForPendingDatagramCount();
530         registerForSatelliteModemStateChanged();
531         registerForServiceStateChanged();
532         mContentResolver = mContext.getContentResolver();
533         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
534 
535         mBTWifiNFCSateReceiver = new BTWifiNFCStateReceiver();
536         mUwbAdapterStateCallback = new UwbAdapterStateCallback();
537         initializeSatelliteModeRadios();
538 
539         ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) {
540             @Override
541             public void onChange(boolean selfChange) {
542                 initializeSatelliteModeRadios();
543             }
544         };
545         if (mContentResolver != null) {
546             mContentResolver.registerContentObserver(
547                     Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS),
548                     false, satelliteModeRadiosContentObserver);
549         }
550 
551         mSatellitePlmnListFromOverlayConfig = readSatellitePlmnsFromOverlayConfig();
552         updateSupportedSatelliteServicesForActiveSubscriptions();
553         mCarrierConfigChangeListener =
554                 (slotIndex, subId, carrierId, specificCarrierId) ->
555                         handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
556         mCarrierConfigManager.registerCarrierConfigChangeListener(
557                         new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
558 
559         mConfigDataUpdatedCallback = new ConfigProviderAdaptor.Callback() {
560             @Override
561             public void onChanged(@Nullable ConfigParser config) {
562                 SatelliteControllerHandlerRequest request =
563                         new SatelliteControllerHandlerRequest(true,
564                                 SatelliteServiceUtils.getPhone());
565                 sendRequestAsync(EVENT_SATELLITE_CONFIG_DATA_UPDATED, request, null);
566             }
567         };
568         TelephonyConfigUpdateInstallReceiver.getInstance()
569                 .registerCallback(Executors.newSingleThreadExecutor(), mConfigDataUpdatedCallback);
570 
571         mDSM.registerForSignalStrengthReportDecision(this, CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING,
572                 null);
573         loadSatelliteSharedPreferences();
574         mWaitTimeForSatelliteEnablingResponse = getWaitForSatelliteEnablingResponseTimeoutMillis();
575         mDemoPointingAlignedDurationMillis = getDemoPointingAlignedDurationMillisFromResources();
576         mDemoPointingNotAlignedDurationMillis =
577                 getDemoPointingNotAlignedDurationMillisFromResources();
578         mSatelliteEmergencyModeDurationMillis =
579                 getSatelliteEmergencyModeDurationFromOverlayConfig(context);
580     }
581 
582     /**
583      * Register a callback to get a updated satellite config data.
584      * @param h Handler to notify
585      * @param what msg.what when the message is delivered
586      * @param obj AsyncResult.userObj when the message is delivered
587      */
registerForConfigUpdateChanged(Handler h, int what, Object obj)588     public void registerForConfigUpdateChanged(Handler h, int what, Object obj) {
589         Registrant r = new Registrant(h, what, obj);
590         mSatelliteConfigUpdateChangedRegistrants.add(r);
591     }
592 
593     /**
594      * Unregister a callback to get a updated satellite config data.
595      * @param h Handler to notify
596      */
unregisterForConfigUpdateChanged(Handler h)597     public void unregisterForConfigUpdateChanged(Handler h) {
598         mSatelliteConfigUpdateChangedRegistrants.remove(h);
599     }
600 
601     /**
602      * Get satelliteConfig from SatelliteConfigParser
603      */
getSatelliteConfig()604     public SatelliteConfig getSatelliteConfig() {
605         SatelliteConfigParser satelliteConfigParser = getSatelliteConfigParser();
606         if (satelliteConfigParser == null) {
607             Log.d(TAG, "satelliteConfigParser is not ready");
608             return null;
609         }
610         return satelliteConfigParser.getConfig();
611     }
612 
613     /**
614      * Get SatelliteConfigParser from TelephonyConfigUpdateInstallReceiver
615      */
616     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getSatelliteConfigParser()617     public SatelliteConfigParser getSatelliteConfigParser() {
618         return (SatelliteConfigParser) TelephonyConfigUpdateInstallReceiver
619                 .getInstance().getConfigParser(DOMAIN_SATELLITE);
620     }
621 
622     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
initializeSatelliteModeRadios()623     protected void initializeSatelliteModeRadios() {
624         if (mContentResolver != null) {
625             IntentFilter radioStateIntentFilter = new IntentFilter();
626 
627             synchronized (mRadioStateLock) {
628                 // Initialize radio states to default value
629                 mDisableBTOnSatelliteEnabled = false;
630                 mDisableNFCOnSatelliteEnabled = false;
631                 mDisableWifiOnSatelliteEnabled = false;
632                 mDisableUWBOnSatelliteEnabled = false;
633 
634                 mBTStateEnabled = false;
635                 mNfcStateEnabled = false;
636                 mWifiStateEnabled = false;
637                 mUwbStateEnabled = false;
638 
639                 // Read satellite mode radios from settings
640                 String satelliteModeRadios = Settings.Global.getString(mContentResolver,
641                         Settings.Global.SATELLITE_MODE_RADIOS);
642                 if (satelliteModeRadios == null) {
643                     ploge("initializeSatelliteModeRadios: satelliteModeRadios is null");
644                     return;
645                 }
646                 plogd("Radios To be checked when satellite is on: " + satelliteModeRadios);
647 
648                 if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) {
649                     BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
650                     if (bluetoothAdapter != null) {
651                         mDisableBTOnSatelliteEnabled = true;
652                         mBTStateEnabled = bluetoothAdapter.isEnabled();
653                         radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
654                     }
655                 }
656 
657                 if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC)) {
658                     Context applicationContext = mContext.getApplicationContext();
659                     NfcAdapter nfcAdapter = null;
660                     if (applicationContext != null) {
661                         nfcAdapter = NfcAdapter.getDefaultAdapter(mContext.getApplicationContext());
662                     }
663                     if (nfcAdapter != null) {
664                         mDisableNFCOnSatelliteEnabled = true;
665                         mNfcStateEnabled = nfcAdapter.isEnabled();
666                         radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
667                     }
668                 }
669 
670                 if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI)) {
671                     WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
672                     if (wifiManager != null) {
673                         mDisableWifiOnSatelliteEnabled = true;
674                         mWifiStateEnabled = wifiManager.isWifiEnabled();
675                         radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
676                     }
677                 }
678 
679                 try {
680                     // Unregister receiver before registering it.
681                     mContext.unregisterReceiver(mBTWifiNFCSateReceiver);
682                 } catch (IllegalArgumentException e) {
683                     plogd("initializeSatelliteModeRadios: unregisterReceiver, e=" + e);
684                 }
685                 mContext.registerReceiver(mBTWifiNFCSateReceiver, radioStateIntentFilter);
686 
687                 if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB)) {
688                     UwbManager uwbManager = mContext.getSystemService(UwbManager.class);
689                     if (uwbManager != null) {
690                         mDisableUWBOnSatelliteEnabled = true;
691                         mUwbStateEnabled = uwbManager.isUwbEnabled();
692                         final long identity = Binder.clearCallingIdentity();
693                         try {
694                             // Unregister callback before registering it.
695                             uwbManager.unregisterAdapterStateCallback(mUwbAdapterStateCallback);
696                             uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(),
697                                     mUwbAdapterStateCallback);
698                         } finally {
699                             Binder.restoreCallingIdentity(identity);
700                         }
701                     }
702                 }
703 
704                 plogd("mDisableBTOnSatelliteEnabled: " + mDisableBTOnSatelliteEnabled
705                         + " mDisableNFCOnSatelliteEnabled: " + mDisableNFCOnSatelliteEnabled
706                         + " mDisableWifiOnSatelliteEnabled: " + mDisableWifiOnSatelliteEnabled
707                         + " mDisableUWBOnSatelliteEnabled: " + mDisableUWBOnSatelliteEnabled);
708 
709                 plogd("mBTStateEnabled: " + mBTStateEnabled
710                         + " mNfcStateEnabled: " + mNfcStateEnabled
711                         + " mWifiStateEnabled: " + mWifiStateEnabled
712                         + " mUwbStateEnabled: " + mUwbStateEnabled);
713             }
714         }
715     }
716 
717     protected class UwbAdapterStateCallback implements UwbManager.AdapterStateCallback {
718 
toString(int state)719         public String toString(int state) {
720             switch (state) {
721                 case UwbManager.AdapterStateCallback.STATE_DISABLED:
722                     return "Disabled";
723 
724                 case UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE:
725                     return "Inactive";
726 
727                 case UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE:
728                     return "Active";
729 
730                 default:
731                     return "";
732             }
733         }
734 
735         @Override
onStateChanged(int state, int reason)736         public void onStateChanged(int state, int reason) {
737             plogd("UwbAdapterStateCallback#onStateChanged() called, state = " + toString(state));
738             plogd("Adapter state changed reason " + String.valueOf(reason));
739             synchronized (mRadioStateLock) {
740                 if (state == UwbManager.AdapterStateCallback.STATE_DISABLED) {
741                     mUwbStateEnabled = false;
742                     evaluateToSendSatelliteEnabledSuccess();
743                 } else {
744                     mUwbStateEnabled = true;
745                 }
746                 plogd("mUwbStateEnabled: " + mUwbStateEnabled);
747             }
748         }
749     }
750 
751     protected class BTWifiNFCStateReceiver extends BroadcastReceiver {
752         @Override
onReceive(Context context, Intent intent)753         public void onReceive(Context context, Intent intent) {
754             final String action = intent.getAction();
755             if (action == null) {
756                 plogd("BTWifiNFCStateReceiver NULL action for intent " + intent);
757                 return;
758             }
759 
760             switch (action) {
761                 case BluetoothAdapter.ACTION_STATE_CHANGED:
762                     int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
763                             BluetoothAdapter.ERROR);
764                     synchronized (mRadioStateLock) {
765                         boolean currentBTStateEnabled = mBTStateEnabled;
766                         if (btState == BluetoothAdapter.STATE_OFF) {
767                             mBTStateEnabled = false;
768                             evaluateToSendSatelliteEnabledSuccess();
769                         } else if (btState == BluetoothAdapter.STATE_ON) {
770                             mBTStateEnabled = true;
771                         }
772                         if (currentBTStateEnabled != mBTStateEnabled) {
773                             plogd("mBTStateEnabled=" + mBTStateEnabled);
774                         }
775                     }
776                     break;
777 
778                 case NfcAdapter.ACTION_ADAPTER_STATE_CHANGED:
779                     int nfcState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1);
780                     synchronized (mRadioStateLock) {
781                         boolean currentNfcStateEnabled = mNfcStateEnabled;
782                         if (nfcState == NfcAdapter.STATE_ON) {
783                             mNfcStateEnabled = true;
784                         } else if (nfcState == NfcAdapter.STATE_OFF) {
785                             mNfcStateEnabled = false;
786                             evaluateToSendSatelliteEnabledSuccess();
787                         }
788                         if (currentNfcStateEnabled != mNfcStateEnabled) {
789                             plogd("mNfcStateEnabled=" + mNfcStateEnabled);
790                         }
791                     }
792                     break;
793 
794                 case WifiManager.WIFI_STATE_CHANGED_ACTION:
795                     int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
796                             WifiManager.WIFI_STATE_UNKNOWN);
797                     synchronized (mRadioStateLock) {
798                         boolean currentWifiStateEnabled = mWifiStateEnabled;
799                         if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
800                             mWifiStateEnabled = true;
801                         } else if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
802                             mWifiStateEnabled = false;
803                             evaluateToSendSatelliteEnabledSuccess();
804                         }
805                         if (currentWifiStateEnabled != mWifiStateEnabled) {
806                             plogd("mWifiStateEnabled=" + mWifiStateEnabled);
807                         }
808                     }
809                     break;
810                 default:
811                     break;
812             }
813         }
814     }
815 
816     private static final class SatelliteControllerHandlerRequest {
817         /** The argument to use for the request */
818         public @NonNull Object argument;
819         /** The caller needs to specify the phone to be used for the request */
820         public @NonNull Phone phone;
821         /** The result of the request that is run on the main thread */
822         public @Nullable Object result;
823 
SatelliteControllerHandlerRequest(Object argument, Phone phone)824         SatelliteControllerHandlerRequest(Object argument, Phone phone) {
825             this.argument = argument;
826             this.phone = phone;
827         }
828     }
829 
830     private static final class RequestSatelliteEnabledArgument {
831         public boolean enableSatellite;
832         public boolean enableDemoMode;
833         public boolean isEmergency;
834         @NonNull public Consumer<Integer> callback;
835         public long requestId;
836 
RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, Consumer<Integer> callback)837         RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode,
838                 boolean isEmergency, Consumer<Integer> callback) {
839             this.enableSatellite = enableSatellite;
840             this.enableDemoMode = enableDemoMode;
841             this.isEmergency = isEmergency;
842             this.callback = callback;
843             this.requestId = sNextSatelliteEnableRequestId.getAndUpdate(
844                     n -> ((n + 1) % Long.MAX_VALUE));
845         }
846     }
847 
848     private static final class RequestHandleSatelliteAttachRestrictionForCarrierArgument {
849         public int subId;
850         @SatelliteManager.SatelliteCommunicationRestrictionReason
851         public int reason;
852         @NonNull public Consumer<Integer> callback;
853 
RequestHandleSatelliteAttachRestrictionForCarrierArgument(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, Consumer<Integer> callback)854         RequestHandleSatelliteAttachRestrictionForCarrierArgument(int subId,
855                 @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
856                 Consumer<Integer> callback) {
857             this.subId = subId;
858             this.reason = reason;
859             this.callback = callback;
860         }
861     }
862 
863     private static final class ProvisionSatelliteServiceArgument {
864         @NonNull public String token;
865         @NonNull public byte[] provisionData;
866         @NonNull public Consumer<Integer> callback;
867         public int subId;
868 
ProvisionSatelliteServiceArgument(String token, byte[] provisionData, Consumer<Integer> callback, int subId)869         ProvisionSatelliteServiceArgument(String token, byte[] provisionData,
870                 Consumer<Integer> callback, int subId) {
871             this.token = token;
872             this.provisionData = provisionData;
873             this.callback = callback;
874             this.subId = subId;
875         }
876     }
877 
878     /**
879      * Arguments to send to SatelliteTransmissionUpdate registrants
880      */
881     public static final class SatelliteTransmissionUpdateArgument {
882         @NonNull public Consumer<Integer> errorCallback;
883         @NonNull public ISatelliteTransmissionUpdateCallback callback;
884         public int subId;
885 
SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback, ISatelliteTransmissionUpdateCallback callback, int subId)886         SatelliteTransmissionUpdateArgument(Consumer<Integer> errorCallback,
887                 ISatelliteTransmissionUpdateCallback callback, int subId) {
888             this.errorCallback = errorCallback;
889             this.callback = callback;
890             this.subId = subId;
891         }
892     }
893 
894     @Override
handleMessage(Message msg)895     public void handleMessage(Message msg) {
896         SatelliteControllerHandlerRequest request;
897         Message onCompleted;
898         AsyncResult ar;
899 
900         switch(msg.what) {
901             case CMD_START_SATELLITE_TRANSMISSION_UPDATES: {
902                 request = (SatelliteControllerHandlerRequest) msg.obj;
903                 onCompleted =
904                         obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
905                 mPointingAppController.startSatelliteTransmissionUpdates(onCompleted);
906                 break;
907             }
908 
909             case EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE: {
910                 handleStartSatelliteTransmissionUpdatesDone((AsyncResult) msg.obj);
911                 break;
912             }
913 
914             case CMD_STOP_SATELLITE_TRANSMISSION_UPDATES: {
915                 request = (SatelliteControllerHandlerRequest) msg.obj;
916                 onCompleted =
917                         obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
918                 mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted);
919                 break;
920             }
921 
922             case EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE: {
923                 ar = (AsyncResult) msg.obj;
924                 request = (SatelliteControllerHandlerRequest) ar.userObj;
925                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
926                         "stopSatelliteTransmissionUpdates");
927                 ((Consumer<Integer>) request.argument).accept(error);
928                 break;
929             }
930 
931             case CMD_PROVISION_SATELLITE_SERVICE: {
932                 request = (SatelliteControllerHandlerRequest) msg.obj;
933                 ProvisionSatelliteServiceArgument argument =
934                         (ProvisionSatelliteServiceArgument) request.argument;
935                 if (mSatelliteProvisionCallbacks.containsKey(argument.subId)) {
936                     argument.callback.accept(
937                             SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS);
938                     notifyRequester(request);
939                     break;
940                 }
941                 mSatelliteProvisionCallbacks.put(argument.subId, argument.callback);
942                 onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request);
943                 // Log the current time for provision triggered
944                 mProvisionMetricsStats.setProvisioningStartTime();
945                 mSatelliteModemInterface.provisionSatelliteService(argument.token,
946                         argument.provisionData, onCompleted);
947                 break;
948             }
949 
950             case EVENT_PROVISION_SATELLITE_SERVICE_DONE: {
951                 ar = (AsyncResult) msg.obj;
952                 request = (SatelliteControllerHandlerRequest) ar.userObj;
953                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
954                         "provisionSatelliteService");
955                 handleEventProvisionSatelliteServiceDone(
956                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
957                 notifyRequester(request);
958                 break;
959             }
960 
961             case CMD_DEPROVISION_SATELLITE_SERVICE: {
962                 request = (SatelliteControllerHandlerRequest) msg.obj;
963                 ProvisionSatelliteServiceArgument argument =
964                         (ProvisionSatelliteServiceArgument) request.argument;
965                 onCompleted = obtainMessage(EVENT_DEPROVISION_SATELLITE_SERVICE_DONE, request);
966                 if (argument.callback != null) {
967                     mProvisionMetricsStats.setProvisioningStartTime();
968                 }
969                 mSatelliteModemInterface.deprovisionSatelliteService(argument.token, onCompleted);
970                 break;
971             }
972 
973             case EVENT_DEPROVISION_SATELLITE_SERVICE_DONE: {
974                 ar = (AsyncResult) msg.obj;
975                 request = (SatelliteControllerHandlerRequest) ar.userObj;
976                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
977                         "deprovisionSatelliteService");
978                 handleEventDeprovisionSatelliteServiceDone(
979                         (ProvisionSatelliteServiceArgument) request.argument, errorCode);
980                 break;
981             }
982 
983             case CMD_SET_SATELLITE_ENABLED: {
984                 request = (SatelliteControllerHandlerRequest) msg.obj;
985                 handleSatelliteEnabled(request);
986                 break;
987             }
988 
989             case EVENT_SET_SATELLITE_ENABLED_DONE: {
990                 ar = (AsyncResult) msg.obj;
991                 request = (SatelliteControllerHandlerRequest) ar.userObj;
992                 RequestSatelliteEnabledArgument argument =
993                         (RequestSatelliteEnabledArgument) request.argument;
994                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled");
995                 plogd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error);
996 
997                 /*
998                  * The timer to wait for EVENT_SET_SATELLITE_ENABLED_DONE might have expired and
999                  * thus the request resources might have been cleaned up.
1000                  */
1001                 if (!shouldProcessEventSetSatelliteEnabledDone(argument)) {
1002                     plogw("The request ID=" + argument.requestId + ", enableSatellite="
1003                             + argument.enableSatellite + " was already processed");
1004                     return;
1005                 }
1006                 stopWaitForSatelliteEnablingResponseTimer(argument);
1007 
1008                 if (error == SATELLITE_RESULT_SUCCESS) {
1009                     if (argument.enableSatellite) {
1010                         synchronized (mSatelliteEnabledRequestLock) {
1011                             mWaitingForRadioDisabled = true;
1012                             setDemoModeEnabled(argument.enableDemoMode);
1013                         }
1014                         setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_TRUE);
1015                         setSettingsKeyToAllowDeviceRotation(SATELLITE_MODE_ENABLED_TRUE);
1016                         evaluateToSendSatelliteEnabledSuccess();
1017                     } else {
1018                         /**
1019                          * Unregister Importance Listener for Pointing UI
1020                          * when Satellite is disabled
1021                          */
1022                         if (mNeedsSatellitePointing) {
1023                             mPointingAppController.removeListenerForPointingUI();
1024                         }
1025                         synchronized (mSatelliteEnabledRequestLock) {
1026                             if (mSatelliteEnabledRequest != null &&
1027                                     mSatelliteEnabledRequest.enableSatellite == true &&
1028                                     argument.enableSatellite == false && mWaitingForRadioDisabled) {
1029                                 // Previous mSatelliteEnabledRequest is successful but waiting for
1030                                 // all radios to be turned off.
1031                                 mSatelliteEnabledRequest.callback.accept(
1032                                         SATELLITE_RESULT_SUCCESS);
1033                             }
1034                         }
1035 
1036                         synchronized (mIsSatelliteEnabledLock) {
1037                             if (!mWaitingForSatelliteModemOff) {
1038                                 moveSatelliteToOffStateAndCleanUpResources(
1039                                         SATELLITE_RESULT_SUCCESS,
1040                                         argument.callback);
1041                             } else {
1042                                 plogd("Wait for satellite modem off before updating satellite"
1043                                         + " modem state");
1044                             }
1045                             mWaitingForDisableSatelliteModemResponse = false;
1046                         }
1047                     }
1048                     // Request Ntn signal strength report when satellite enabled or disabled done.
1049                     mLatestRequestedStateForNtnSignalStrengthReport.set(argument.enableSatellite);
1050                     updateNtnSignalStrengthReporting(argument.enableSatellite);
1051                 } else {
1052                     synchronized (mSatelliteEnabledRequestLock) {
1053                         if (mSatelliteEnabledRequest != null &&
1054                                 mSatelliteEnabledRequest.enableSatellite == true &&
1055                                 argument.enableSatellite == false && mWaitingForRadioDisabled) {
1056                             // Previous mSatelliteEnabledRequest is successful but waiting for
1057                             // all radios to be turned off.
1058                             mSatelliteEnabledRequest.callback.accept(
1059                                     SATELLITE_RESULT_SUCCESS);
1060                         }
1061                     }
1062                     notifyEnablementFailedToSatelliteSessionController();
1063                     resetSatelliteEnabledRequest();
1064 
1065                     // If Satellite enable/disable request returned Error, no need to wait for radio
1066                     argument.callback.accept(error);
1067                 }
1068 
1069                 if (argument.enableSatellite) {
1070                     mSessionMetricsStats.setInitializationResult(error)
1071                             .setSatelliteTechnology(getSupportedNtnRadioTechnology())
1072                             .setInitializationProcessingTime(
1073                                     System.currentTimeMillis() - mSessionProcessingTimeStamp)
1074                             .setIsDemoMode(mIsDemoModeEnabled);
1075                     mSessionProcessingTimeStamp = 0;
1076 
1077                     if (error == SATELLITE_RESULT_SUCCESS) {
1078                         mControllerMetricsStats.onSatelliteEnabled();
1079                         mControllerMetricsStats.reportServiceEnablementSuccessCount();
1080                     } else {
1081                         mSessionMetricsStats.reportSessionMetrics();
1082                         mSessionStartTimeStamp = 0;
1083                         mControllerMetricsStats.reportServiceEnablementFailCount();
1084                     }
1085                 } else {
1086                     mSessionMetricsStats.setTerminationResult(error)
1087                             .setTerminationProcessingTime(System.currentTimeMillis()
1088                                     - mSessionProcessingTimeStamp)
1089                             .setSessionDurationSec(calculateSessionDurationTimeSec())
1090                             .reportSessionMetrics();
1091                     mSessionStartTimeStamp = 0;
1092                     mSessionProcessingTimeStamp = 0;
1093 
1094                     mControllerMetricsStats.onSatelliteDisabled();
1095 
1096                     handlePersistentLoggingOnSessionEnd(mIsEmergency);
1097 
1098                     synchronized (mIsSatelliteEnabledLock) {
1099                         mWaitingForDisableSatelliteModemResponse = false;
1100                     }
1101                 }
1102                 break;
1103             }
1104 
1105             case EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT:
1106                 handleEventWaitForSatelliteEnablingResponseTimedOut(
1107                         (RequestSatelliteEnabledArgument) msg.obj);
1108                 break;
1109 
1110             case CMD_IS_SATELLITE_ENABLED: {
1111                 request = (SatelliteControllerHandlerRequest) msg.obj;
1112                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request);
1113                 mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted);
1114                 break;
1115             }
1116 
1117             case EVENT_IS_SATELLITE_ENABLED_DONE: {
1118                 ar = (AsyncResult) msg.obj;
1119                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1120                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1121                         "isSatelliteEnabled");
1122                 Bundle bundle = new Bundle();
1123                 if (error == SATELLITE_RESULT_SUCCESS) {
1124                     if (ar.result == null) {
1125                         ploge("isSatelliteEnabled: result is null");
1126                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1127                     } else {
1128                         boolean enabled = ((int[]) ar.result)[0] == 1;
1129                         if (DBG) plogd("isSatelliteEnabled: " + enabled);
1130                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled);
1131                         updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE");
1132                     }
1133                 } else if (error == SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
1134                     updateSatelliteSupportedStateWhenSatelliteServiceConnected(false);
1135                 }
1136                 ((ResultReceiver) request.argument).send(error, bundle);
1137                 break;
1138             }
1139 
1140             case CMD_IS_SATELLITE_SUPPORTED: {
1141                 request = (SatelliteControllerHandlerRequest) msg.obj;
1142                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request);
1143                 mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted);
1144                 break;
1145             }
1146 
1147             case EVENT_IS_SATELLITE_SUPPORTED_DONE: {
1148                 ar = (AsyncResult) msg.obj;
1149                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1150                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported");
1151                 Bundle bundle = new Bundle();
1152                 if (error == SATELLITE_RESULT_SUCCESS) {
1153                     if (ar.result == null) {
1154                         ploge("isSatelliteSupported: result is null");
1155                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1156                     } else {
1157                         boolean supported = (boolean) ar.result;
1158                         plogd("isSatelliteSupported: " + supported);
1159                         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported);
1160                         updateSatelliteSupportedStateWhenSatelliteServiceConnected(supported);
1161                     }
1162                 }
1163                 ((ResultReceiver) request.argument).send(error, bundle);
1164                 break;
1165             }
1166 
1167             case CMD_GET_SATELLITE_CAPABILITIES: {
1168                 request = (SatelliteControllerHandlerRequest) msg.obj;
1169                 onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request);
1170                 mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted);
1171                 break;
1172             }
1173 
1174             case EVENT_GET_SATELLITE_CAPABILITIES_DONE: {
1175                 ar = (AsyncResult) msg.obj;
1176                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1177                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1178                         "getSatelliteCapabilities");
1179                 Bundle bundle = new Bundle();
1180                 if (error == SATELLITE_RESULT_SUCCESS) {
1181                     if (ar.result == null) {
1182                         ploge("getSatelliteCapabilities: result is null");
1183                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1184                     } else {
1185                         SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result;
1186                         synchronized (mNeedsSatellitePointingLock) {
1187                             mNeedsSatellitePointing = capabilities.isPointingRequired();
1188                         }
1189                         if (DBG) plogd("getSatelliteCapabilities: " + capabilities);
1190                         bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
1191                                 capabilities);
1192                         synchronized (mSatelliteCapabilitiesLock) {
1193                             mSatelliteCapabilities = capabilities;
1194                         }
1195                     }
1196                 }
1197                 ((ResultReceiver) request.argument).send(error, bundle);
1198                 break;
1199             }
1200 
1201             case CMD_GET_TIME_SATELLITE_NEXT_VISIBLE: {
1202                 request = (SatelliteControllerHandlerRequest) msg.obj;
1203                 onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE,
1204                         request);
1205                 mSatelliteModemInterface.requestTimeForNextSatelliteVisibility(onCompleted);
1206                 break;
1207             }
1208 
1209             case EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE: {
1210                 ar = (AsyncResult) msg.obj;
1211                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1212                 int error = SatelliteServiceUtils.getSatelliteError(ar,
1213                         "requestTimeForNextSatelliteVisibility");
1214                 Bundle bundle = new Bundle();
1215                 if (error == SATELLITE_RESULT_SUCCESS) {
1216                     if (ar.result == null) {
1217                         ploge("requestTimeForNextSatelliteVisibility: result is null");
1218                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1219                     } else {
1220                         int nextVisibilityDuration = ((int[]) ar.result)[0];
1221                         if (DBG) {
1222                             plogd("requestTimeForNextSatelliteVisibility: "
1223                                     + nextVisibilityDuration);
1224                         }
1225                         bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY,
1226                                 nextVisibilityDuration);
1227                     }
1228                 }
1229                 ((ResultReceiver) request.argument).send(error, bundle);
1230                 break;
1231             }
1232 
1233             case EVENT_RADIO_STATE_CHANGED: {
1234                 synchronized (mIsRadioOnLock) {
1235                     logd("EVENT_RADIO_STATE_CHANGED: radioState=" + mCi.getRadioState());
1236                     if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
1237                         mIsRadioOn = true;
1238                     } else if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) {
1239                         resetCarrierRoamingSatelliteModeParams();
1240                     }
1241                 }
1242 
1243                 if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE) {
1244                     if (mSatelliteModemInterface.isSatelliteServiceConnected()) {
1245                         synchronized (mIsSatelliteSupportedLock) {
1246                             if (mIsSatelliteSupported == null || !mIsSatelliteSupported) {
1247                                 ResultReceiver receiver = new ResultReceiver(this) {
1248                                     @Override
1249                                     protected void onReceiveResult(
1250                                             int resultCode, Bundle resultData) {
1251                                         plogd("onRadioStateChanged.requestIsSatelliteSupported: "
1252                                                 + "resultCode=" + resultCode
1253                                                 + ", resultData=" + resultData);
1254                                     }
1255                                 };
1256                                 sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, receiver, null);
1257                             }
1258                         }
1259                     }
1260                 }
1261                 break;
1262             }
1263 
1264             case CMD_IS_SATELLITE_PROVISIONED: {
1265                 request = (SatelliteControllerHandlerRequest) msg.obj;
1266                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request);
1267                 mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted);
1268                 break;
1269             }
1270 
1271             case EVENT_IS_SATELLITE_PROVISIONED_DONE: {
1272                 handleIsSatelliteProvisionedDoneEvent((AsyncResult) msg.obj);
1273                 break;
1274             }
1275 
1276             case EVENT_SATELLITE_PROVISION_STATE_CHANGED:
1277                 ar = (AsyncResult) msg.obj;
1278                 if (ar.result == null) {
1279                     ploge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null");
1280                 } else {
1281                     handleEventSatelliteProvisionStateChanged((boolean) ar.result);
1282                 }
1283                 break;
1284 
1285             case EVENT_PENDING_DATAGRAMS:
1286                 plogd("Received EVENT_PENDING_DATAGRAMS");
1287                 IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
1288                     @Override
1289                     public void accept(int result) {
1290                         plogd("pollPendingSatelliteDatagram result: " + result);
1291                     }
1292                 };
1293                 pollPendingDatagrams(
1294                         SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback);
1295                 break;
1296 
1297             case EVENT_SATELLITE_MODEM_STATE_CHANGED:
1298                 ar = (AsyncResult) msg.obj;
1299                 if (ar.result == null) {
1300                     ploge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null");
1301                 } else {
1302                     handleEventSatelliteModemStateChanged((int) ar.result);
1303                 }
1304                 break;
1305 
1306             case EVENT_SET_SATELLITE_PLMN_INFO_DONE:
1307                 handleSetSatellitePlmnInfoDoneEvent(msg);
1308                 break;
1309 
1310             case CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE: {
1311                 plogd("CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE");
1312                 request = (SatelliteControllerHandlerRequest) msg.obj;
1313                 handleRequestSatelliteAttachRestrictionForCarrierCmd(request);
1314                 break;
1315             }
1316 
1317             case EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE: {
1318                 ar = (AsyncResult) msg.obj;
1319                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1320                 RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
1321                         (RequestHandleSatelliteAttachRestrictionForCarrierArgument)
1322                                 request.argument;
1323                 int subId = argument.subId;
1324                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
1325                         "requestSetSatelliteEnabledForCarrier");
1326 
1327                 synchronized (mIsSatelliteEnabledLock) {
1328                     if (error == SATELLITE_RESULT_SUCCESS) {
1329                         boolean enableSatellite = mSatelliteAttachRestrictionForCarrierArray
1330                                 .getOrDefault(argument.subId, Collections.emptySet()).isEmpty();
1331                         mIsSatelliteAttachEnabledForCarrierArrayPerSub.put(subId, enableSatellite);
1332                     } else {
1333                         mIsSatelliteAttachEnabledForCarrierArrayPerSub.remove(subId);
1334                     }
1335                 }
1336 
1337                 argument.callback.accept(error);
1338                 break;
1339             }
1340 
1341             case CMD_REQUEST_NTN_SIGNAL_STRENGTH: {
1342                 plogd("CMD_REQUEST_NTN_SIGNAL_STRENGTH");
1343                 request = (SatelliteControllerHandlerRequest) msg.obj;
1344                 onCompleted = obtainMessage(EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE, request);
1345                 mSatelliteModemInterface.requestNtnSignalStrength(onCompleted);
1346                 break;
1347             }
1348 
1349             case EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: {
1350                 ar = (AsyncResult) msg.obj;
1351                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1352                 ResultReceiver result = (ResultReceiver) request.argument;
1353                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
1354                         "requestNtnSignalStrength");
1355                 if (errorCode == SATELLITE_RESULT_SUCCESS) {
1356                     NtnSignalStrength ntnSignalStrength = (NtnSignalStrength) ar.result;
1357                     if (ntnSignalStrength != null) {
1358                         synchronized (mNtnSignalsStrengthLock) {
1359                             mNtnSignalStrength = ntnSignalStrength;
1360                         }
1361                         Bundle bundle = new Bundle();
1362                         bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, ntnSignalStrength);
1363                         result.send(SATELLITE_RESULT_SUCCESS, bundle);
1364                     } else {
1365                         synchronized (mNtnSignalsStrengthLock) {
1366                             if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
1367                                 mNtnSignalStrength = new NtnSignalStrength(
1368                                         NTN_SIGNAL_STRENGTH_NONE);
1369                             }
1370                         }
1371                         ploge("EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: ntnSignalStrength is null");
1372                         result.send(SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED, null);
1373                     }
1374                 } else {
1375                     synchronized (mNtnSignalsStrengthLock) {
1376                         if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
1377                             mNtnSignalStrength = new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
1378                         }
1379                     }
1380                     result.send(errorCode, null);
1381                 }
1382                 break;
1383             }
1384 
1385             case EVENT_NTN_SIGNAL_STRENGTH_CHANGED: {
1386                 ar = (AsyncResult) msg.obj;
1387                 if (ar.result == null) {
1388                     ploge("EVENT_NTN_SIGNAL_STRENGTH_CHANGED: result is null");
1389                 } else {
1390                     handleEventNtnSignalStrengthChanged((NtnSignalStrength) ar.result);
1391                 }
1392                 break;
1393             }
1394 
1395             case CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: {
1396                 ar = (AsyncResult) msg.obj;
1397                 boolean shouldReport = (boolean) ar.result;
1398                 if (DBG) {
1399                     plogd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: shouldReport=" + shouldReport);
1400                 }
1401                 handleCmdUpdateNtnSignalStrengthReporting(shouldReport);
1402                 break;
1403             }
1404 
1405             case EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: {
1406                 ar = (AsyncResult) msg.obj;
1407                 request = (SatelliteControllerHandlerRequest) ar.userObj;
1408                 boolean shouldReport = (boolean) request.argument;
1409                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
1410                         "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: shouldReport="
1411                                 + shouldReport);
1412                 if (errorCode == SATELLITE_RESULT_SUCCESS) {
1413                     mIsModemEnabledReportingNtnSignalStrength.set(shouldReport);
1414                     if (mLatestRequestedStateForNtnSignalStrengthReport.get()
1415                             != mIsModemEnabledReportingNtnSignalStrength.get()) {
1416                         logd("mLatestRequestedStateForNtnSignalStrengthReport does not match with "
1417                                 + "mIsModemEnabledReportingNtnSignalStrength");
1418                         updateNtnSignalStrengthReporting(
1419                                 mLatestRequestedStateForNtnSignalStrengthReport.get());
1420                     }
1421                 } else {
1422                     loge(((boolean) request.argument ? "startSendingNtnSignalStrength"
1423                             : "stopSendingNtnSignalStrength") + "returns " + errorCode);
1424                 }
1425                 break;
1426             }
1427 
1428             case EVENT_SERVICE_STATE_CHANGED: {
1429                 handleEventServiceStateChanged();
1430                 break;
1431             }
1432 
1433             case EVENT_SATELLITE_CAPABILITIES_CHANGED: {
1434                 ar = (AsyncResult) msg.obj;
1435                 if (ar.result == null) {
1436                     ploge("EVENT_SATELLITE_CAPABILITIES_CHANGED: result is null");
1437                 } else {
1438                     handleEventSatelliteCapabilitiesChanged((SatelliteCapabilities) ar.result);
1439                 }
1440                 break;
1441             }
1442 
1443             case EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: {
1444                 ar = (AsyncResult) msg.obj;
1445                 if (ar.result == null) {
1446                     ploge("EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: result is null");
1447                 } else {
1448                     handleEventSatelliteSupportedStateChanged((boolean) ar.result);
1449                 }
1450                 break;
1451             }
1452 
1453             case EVENT_SATELLITE_CONFIG_DATA_UPDATED: {
1454                 handleEventConfigDataUpdated();
1455                 mSatelliteConfigUpdateChangedRegistrants.notifyRegistrants();
1456                 break;
1457             }
1458 
1459             case EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT: {
1460                 int phoneId = (int) msg.obj;
1461                 Phone phone = PhoneFactory.getPhone(phoneId);
1462                 updateLastNotifiedNtnModeAndNotify(phone);
1463                 break;
1464             }
1465 
1466             default:
1467                 Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
1468                         msg.what);
1469                 break;
1470         }
1471     }
1472 
handleEventConfigDataUpdated()1473     private void handleEventConfigDataUpdated() {
1474         updateSupportedSatelliteServicesForActiveSubscriptions();
1475         int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
1476         if (activeSubIds != null) {
1477             for (int subId : activeSubIds) {
1478                 processNewCarrierConfigData(subId);
1479             }
1480         } else {
1481             ploge("updateSupportedSatelliteServicesForActiveSubscriptions: "
1482                     + "activeSubIds is null");
1483         }
1484     }
1485 
notifyRequester(SatelliteControllerHandlerRequest request)1486     private void notifyRequester(SatelliteControllerHandlerRequest request) {
1487         synchronized (request) {
1488             request.notifyAll();
1489         }
1490     }
1491 
1492     /**
1493      * Request to enable or disable the satellite modem and demo mode. If the satellite modem is
1494      * enabled, this will also disable the cellular modem, and if the satellite modem is disabled,
1495      * this will also re-enable the cellular modem.
1496      *
1497      * @param subId The subId of the subscription to set satellite enabled for.
1498      * @param enableSatellite {@code true} to enable the satellite modem and
1499      *                        {@code false} to disable.
1500      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
1501      * @param isEmergency {@code true} to enable emergency mode, {@code false} otherwise.
1502      * @param callback The callback to get the error code of the request.
1503      */
requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, @NonNull IIntegerConsumer callback)1504     public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode,
1505             boolean isEmergency, @NonNull IIntegerConsumer callback) {
1506         plogd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite
1507                 + " enableDemoMode: " + enableDemoMode + " isEmergency: " + isEmergency);
1508         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1509         int error = evaluateOemSatelliteRequestAllowed(true);
1510         if (error != SATELLITE_RESULT_SUCCESS) {
1511             sendErrorAndReportSessionMetrics(error, result);
1512             return;
1513         }
1514 
1515         if (enableSatellite) {
1516             synchronized (mIsRadioOnLock) {
1517                 if (!mIsRadioOn) {
1518                     ploge("Radio is not on, can not enable satellite");
1519                     sendErrorAndReportSessionMetrics(
1520                             SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE, result);
1521                     return;
1522                 }
1523             }
1524         } else {
1525             /* if disable satellite, always assume demo is also disabled */
1526             enableDemoMode = false;
1527         }
1528 
1529         synchronized (mIsSatelliteEnabledLock) {
1530             if (mIsSatelliteEnabled != null) {
1531                 if (mIsSatelliteEnabled == enableSatellite) {
1532                     if (enableDemoMode != mIsDemoModeEnabled) {
1533                         ploge("Received invalid demo mode while satellite session is enabled"
1534                                 + " enableDemoMode = " + enableDemoMode);
1535                         sendErrorAndReportSessionMetrics(
1536                                 SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS, result);
1537                         return;
1538                     } else {
1539                         plogd("Enable request matches with current state"
1540                                 + " enableSatellite = " + enableSatellite);
1541                         sendErrorAndReportSessionMetrics(
1542                                 SatelliteManager.SATELLITE_RESULT_SUCCESS, result);
1543                         return;
1544                     }
1545                 }
1546             }
1547         }
1548 
1549         RequestSatelliteEnabledArgument request =
1550                 new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, isEmergency,
1551                         result);
1552         /**
1553          * Multiple satellite enabled requests are handled as below:
1554          * 1. If there are no ongoing requests, store current request in mSatelliteEnabledRequest
1555          * 2. If there is a ongoing request, then:
1556          *      1. ongoing request = enable, current request = enable: return IN_PROGRESS error
1557          *      2. ongoing request = disable, current request = disable: return IN_PROGRESS error
1558          *      3. ongoing request = disable, current request = enable: return
1559          *      SATELLITE_RESULT_ERROR error
1560          *      4. ongoing request = enable, current request = disable: send request to modem
1561          */
1562         synchronized (mSatelliteEnabledRequestLock) {
1563             if (mSatelliteEnabledRequest == null) {
1564                 mSatelliteEnabledRequest = request;
1565             } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) {
1566                 plogd("requestSatelliteEnabled enableSatellite: " + enableSatellite
1567                         + " is already in progress.");
1568                 sendErrorAndReportSessionMetrics(
1569                         SatelliteManager.SATELLITE_RESULT_REQUEST_IN_PROGRESS, result);
1570                 return;
1571             } else if (mSatelliteEnabledRequest.enableSatellite == false
1572                     && request.enableSatellite == true) {
1573                 plogd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " cannot be "
1574                         + "processed. Disable satellite is already in progress.");
1575                 sendErrorAndReportSessionMetrics(
1576                         SatelliteManager.SATELLITE_RESULT_ERROR, result);
1577                 return;
1578             }
1579         }
1580 
1581         sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
1582     }
1583 
1584     /**
1585      * Request to get whether the satellite modem is enabled.
1586      *
1587      * @param subId The subId of the subscription to check whether satellite is enabled for.
1588      * @param result The result receiver that returns whether the satellite modem is enabled
1589      *               if the request is successful or an error code if the request failed.
1590      */
requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result)1591     public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) {
1592         int error = evaluateOemSatelliteRequestAllowed(false);
1593         if (error != SATELLITE_RESULT_SUCCESS) {
1594             result.send(error, null);
1595             return;
1596         }
1597 
1598         synchronized (mIsSatelliteEnabledLock) {
1599             if (mIsSatelliteEnabled != null) {
1600                 /* We have already successfully queried the satellite modem. */
1601                 Bundle bundle = new Bundle();
1602                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, mIsSatelliteEnabled);
1603                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
1604                 return;
1605             }
1606         }
1607 
1608         sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, null);
1609     }
1610 
1611     /**
1612      * Get whether the satellite modem is enabled.
1613      * This will return the cached value instead of querying the satellite modem.
1614      *
1615      * @return {@code true} if the satellite modem is enabled and {@code false} otherwise.
1616      */
isSatelliteEnabled()1617     public boolean isSatelliteEnabled() {
1618         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1619             plogd("isSatelliteEnabled: oemEnabledSatelliteFlag is disabled");
1620             return false;
1621         }
1622         if (mIsSatelliteEnabled == null) return false;
1623         return mIsSatelliteEnabled;
1624     }
1625 
1626     /**
1627      * Get whether satellite modem is being enabled.
1628      *
1629      * @return {@code true} if the satellite modem is being enabled and {@code false} otherwise.
1630      */
isSatelliteBeingEnabled()1631     public boolean isSatelliteBeingEnabled() {
1632         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1633             plogd("isSatelliteBeingEnabled: oemEnabledSatelliteFlag is disabled");
1634             return false;
1635         }
1636 
1637         if (mSatelliteSessionController != null) {
1638             return mSatelliteSessionController.isInEnablingState();
1639         }
1640         return false;
1641     }
1642 
1643     /**
1644      * Request to get whether the satellite service demo mode is enabled.
1645      *
1646      * @param subId The subId of the subscription to check whether the satellite demo mode
1647      *              is enabled for.
1648      * @param result The result receiver that returns whether the satellite demo mode is enabled
1649      *               if the request is successful or an error code if the request failed.
1650      */
requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result)1651     public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) {
1652         int error = evaluateOemSatelliteRequestAllowed(true);
1653         if (error != SATELLITE_RESULT_SUCCESS) {
1654             result.send(error, null);
1655             return;
1656         }
1657 
1658         final Bundle bundle = new Bundle();
1659         bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled);
1660         result.send(SATELLITE_RESULT_SUCCESS, bundle);
1661     }
1662 
1663     /**
1664      * Get whether the satellite service demo mode is enabled.
1665      *
1666      * @return {@code true} if the satellite demo mode is enabled and {@code false} otherwise.
1667      */
isDemoModeEnabled()1668     public boolean isDemoModeEnabled() {
1669         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1670             plogd("isDemoModeEnabled: oemEnabledSatelliteFlag is disabled");
1671             return false;
1672         }
1673         return mIsDemoModeEnabled;
1674     }
1675 
1676     /**
1677      * Request to get whether the satellite service is supported on the device.
1678      *
1679      * @param subId The subId of the subscription to check satellite service support for.
1680      * @param result The result receiver that returns whether the satellite service is supported on
1681      *               the device if the request is successful or an error code if the request failed.
1682      */
requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result)1683     public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) {
1684         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1685             plogd("requestIsSatelliteSupported: oemEnabledSatelliteFlag is disabled");
1686             result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
1687             return;
1688         }
1689         synchronized (mIsSatelliteSupportedLock) {
1690             if (mIsSatelliteSupported != null) {
1691                 /* We have already successfully queried the satellite modem. */
1692                 Bundle bundle = new Bundle();
1693                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported);
1694                 bundle.putInt(SATELLITE_SUBSCRIPTION_ID, subId);
1695                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
1696                 return;
1697             }
1698         }
1699 
1700         sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, null);
1701     }
1702 
1703     /**
1704      * Request to get the {@link SatelliteCapabilities} of the satellite service.
1705      *
1706      * @param subId The subId of the subscription to get the satellite capabilities for.
1707      * @param result The result receiver that returns the {@link SatelliteCapabilities}
1708      *               if the request is successful or an error code if the request failed.
1709      */
requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result)1710     public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) {
1711         int error = evaluateOemSatelliteRequestAllowed(false);
1712         if (error != SATELLITE_RESULT_SUCCESS) {
1713             result.send(error, null);
1714             return;
1715         }
1716 
1717         synchronized (mSatelliteCapabilitiesLock) {
1718             if (mSatelliteCapabilities != null) {
1719                 Bundle bundle = new Bundle();
1720                 bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
1721                         mSatelliteCapabilities);
1722                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
1723                 return;
1724             }
1725         }
1726 
1727         sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, null);
1728     }
1729 
1730     /**
1731      * Start receiving satellite transmission updates.
1732      * This can be called by the pointing UI when the user starts pointing to the satellite.
1733      * Modem should continue to report the pointing input as the device or satellite moves.
1734      *
1735      * @param subId The subId of the subscription to start satellite transmission updates for.
1736      * @param errorCallback The callback to get the error code of the request.
1737      * @param callback The callback to notify of satellite transmission updates.
1738      */
startSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)1739     public void startSatelliteTransmissionUpdates(int subId,
1740             @NonNull IIntegerConsumer errorCallback,
1741             @NonNull ISatelliteTransmissionUpdateCallback callback) {
1742         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
1743         int error = evaluateOemSatelliteRequestAllowed(true);
1744         if (error != SATELLITE_RESULT_SUCCESS) {
1745             result.accept(error);
1746             return;
1747         }
1748 
1749         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1750         mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback);
1751         sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES,
1752                 new SatelliteTransmissionUpdateArgument(result, callback, validSubId), null);
1753     }
1754 
1755     /**
1756      * Stop receiving satellite transmission updates.
1757      * This can be called by the pointing UI when the user stops pointing to the satellite.
1758      *
1759      * @param subId The subId of the subscription to stop satellite transmission updates for.
1760      * @param errorCallback The callback to get the error code of the request.
1761      * @param callback The callback that was passed to {@link #startSatelliteTransmissionUpdates(
1762      *                 int, IIntegerConsumer, ISatelliteTransmissionUpdateCallback)}.
1763      */
stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback)1764     public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback,
1765             @NonNull ISatelliteTransmissionUpdateCallback callback) {
1766         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
1767         int error = evaluateOemSatelliteRequestAllowed(true);
1768         if (error != SATELLITE_RESULT_SUCCESS) {
1769             result.accept(error);
1770             return;
1771         }
1772 
1773         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1774         mPointingAppController.unregisterForSatelliteTransmissionUpdates(
1775                 validSubId, result, callback);
1776 
1777         // Even if handler is null - which means there are no listeners, the modem command to stop
1778         // satellite transmission updates might have failed. The callers might want to retry
1779         // sending the command. Thus, we always need to send this command to the modem.
1780         sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, null);
1781     }
1782 
1783     /**
1784      * Register the subscription with a satellite provider.
1785      * This is needed to register the subscription if the provider allows dynamic registration.
1786      *
1787      * @param subId The subId of the subscription to be provisioned.
1788      * @param token The token to be used as a unique identifier for provisioning with satellite
1789      *              gateway.
1790      * @param provisionData Data from the provisioning app that can be used by provisioning server
1791      * @param callback The callback to get the error code of the request.
1792      *
1793      * @return The signal transport used by the caller to cancel the provision request,
1794      *         or {@code null} if the request failed.
1795      */
provisionSatelliteService(int subId, @NonNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer callback)1796     @Nullable public ICancellationSignal provisionSatelliteService(int subId,
1797             @NonNull String token, @NonNull byte[] provisionData,
1798             @NonNull IIntegerConsumer callback) {
1799         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1800         int error = evaluateOemSatelliteRequestAllowed(false);
1801         if (error != SATELLITE_RESULT_SUCCESS) {
1802             result.accept(error);
1803             return null;
1804         }
1805 
1806         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1807         if (mSatelliteProvisionCallbacks.containsKey(validSubId)) {
1808             result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS);
1809             return null;
1810         }
1811 
1812         Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
1813         if (satelliteProvisioned != null && satelliteProvisioned) {
1814             result.accept(SATELLITE_RESULT_SUCCESS);
1815             return null;
1816         }
1817 
1818         sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE,
1819                 new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId),
1820                 null);
1821 
1822         ICancellationSignal cancelTransport = CancellationSignal.createTransport();
1823         CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> {
1824             sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
1825                     new ProvisionSatelliteServiceArgument(token, provisionData, null,
1826                             validSubId), null);
1827             mProvisionMetricsStats.setIsCanceled(true);
1828         });
1829         return cancelTransport;
1830     }
1831 
1832     /**
1833      * Unregister the device/subscription with the satellite provider.
1834      * This is needed if the provider allows dynamic registration. Once deprovisioned,
1835      * {@link android.telephony.satellite.SatelliteProvisionStateCallback
1836      * #onSatelliteProvisionStateChanged(boolean)}
1837      * should report as deprovisioned.
1838      *
1839      * @param subId The subId of the subscription to be deprovisioned.
1840      * @param token The token of the device/subscription to be deprovisioned.
1841      * @param callback The callback to get the error code of the request.
1842      */
deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback)1843     public void deprovisionSatelliteService(int subId,
1844             @NonNull String token, @NonNull IIntegerConsumer callback) {
1845         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
1846         int error = evaluateOemSatelliteRequestAllowed(false);
1847         if (error != SATELLITE_RESULT_SUCCESS) {
1848             result.accept(error);
1849             return;
1850         }
1851 
1852         Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
1853         if (satelliteProvisioned == null) {
1854             result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
1855             return;
1856         }
1857         if (!satelliteProvisioned) {
1858             result.accept(SATELLITE_RESULT_SUCCESS);
1859             return;
1860         }
1861 
1862         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
1863         sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
1864                 new ProvisionSatelliteServiceArgument(token, null, result, validSubId),
1865                 null);
1866     }
1867 
1868     /**
1869      * Registers for the satellite provision state changed.
1870      *
1871      * @param subId The subId of the subscription to register for provision state changed.
1872      * @param callback The callback to handle the satellite provision state changed event.
1873      *
1874      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
1875      */
registerForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback)1876     @SatelliteManager.SatelliteResult public int registerForSatelliteProvisionStateChanged(
1877             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
1878         int error = evaluateOemSatelliteRequestAllowed(false);
1879         if (error != SATELLITE_RESULT_SUCCESS) {
1880             return error;
1881         }
1882 
1883         mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback);
1884         return SATELLITE_RESULT_SUCCESS;
1885     }
1886 
1887     /**
1888      * Unregisters for the satellite provision state changed.
1889      * If callback was not registered before, the request will be ignored.
1890      *
1891      * @param subId The subId of the subscription to unregister for provision state changed.
1892      * @param callback The callback that was passed to
1893      * {@link #registerForSatelliteProvisionStateChanged(int, ISatelliteProvisionStateCallback)}.
1894      */
unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback)1895     public void unregisterForSatelliteProvisionStateChanged(
1896             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
1897         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1898             plogd("unregisterForSatelliteProvisionStateChanged: "
1899                     + "oemEnabledSatelliteFlag is disabled");
1900             return;
1901         }
1902         mSatelliteProvisionStateChangedListeners.remove(callback.asBinder());
1903     }
1904 
1905     /**
1906      * Request to get whether the device is provisioned with a satellite provider.
1907      *
1908      * @param subId The subId of the subscription to get whether the device is provisioned for.
1909      * @param result The result receiver that returns whether the device is provisioned with a
1910      *               satellite provider if the request is successful or an error code if the
1911      *               request failed.
1912      */
requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result)1913     public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) {
1914         int error = evaluateOemSatelliteRequestAllowed(false);
1915         if (error != SATELLITE_RESULT_SUCCESS) {
1916             result.send(error, null);
1917             return;
1918         }
1919 
1920         synchronized (mSatelliteViaOemProvisionLock) {
1921             if (mIsSatelliteViaOemProvisioned != null) {
1922                 Bundle bundle = new Bundle();
1923                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED,
1924                         mIsSatelliteViaOemProvisioned);
1925                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
1926                 return;
1927             }
1928         }
1929 
1930         sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, null);
1931     }
1932 
1933     /**
1934      * Registers for modem state changed from satellite modem.
1935      *
1936      * @param subId The subId of the subscription to register for satellite modem state changed.
1937      * @param callback The callback to handle the satellite modem state changed event.
1938      *
1939      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
1940      */
registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteModemStateCallback callback)1941     @SatelliteManager.SatelliteResult public int registerForSatelliteModemStateChanged(int subId,
1942             @NonNull ISatelliteModemStateCallback callback) {
1943         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1944             plogd("registerForSatelliteModemStateChanged: oemEnabledSatelliteFlag is disabled");
1945             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
1946         }
1947         if (mSatelliteSessionController != null) {
1948             mSatelliteSessionController.registerForSatelliteModemStateChanged(callback);
1949         } else {
1950             ploge("registerForSatelliteModemStateChanged: mSatelliteSessionController"
1951                     + " is not initialized yet");
1952             return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
1953         }
1954         return SATELLITE_RESULT_SUCCESS;
1955     }
1956 
1957     /**
1958      * Unregisters for modem state changed from satellite modem.
1959      * If callback was not registered before, the request will be ignored.
1960      *
1961      * @param subId The subId of the subscription to unregister for satellite modem state changed.
1962      * @param callback The callback that was passed to
1963      * {@link #registerForSatelliteModemStateChanged(int, ISatelliteModemStateCallback)}.
1964      */
unregisterForModemStateChanged(int subId, @NonNull ISatelliteModemStateCallback callback)1965     public void unregisterForModemStateChanged(int subId,
1966             @NonNull ISatelliteModemStateCallback callback) {
1967         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1968             plogd("unregisterForModemStateChanged: oemEnabledSatelliteFlag is disabled");
1969             return;
1970         }
1971         if (mSatelliteSessionController != null) {
1972             mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback);
1973         } else {
1974             ploge("unregisterForModemStateChanged: mSatelliteSessionController"
1975                     + " is not initialized yet");
1976         }
1977     }
1978 
1979     /**
1980      * Register to receive incoming datagrams over satellite.
1981      *
1982      * @param subId The subId of the subscription to register for incoming satellite datagrams.
1983      * @param callback The callback to handle incoming datagrams over satellite.
1984      *
1985      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
1986      */
registerForIncomingDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)1987     @SatelliteManager.SatelliteResult public int registerForIncomingDatagram(int subId,
1988             @NonNull ISatelliteDatagramCallback callback) {
1989         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
1990             plogd("registerForIncomingDatagram: oemEnabledSatelliteFlag is disabled");
1991             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
1992         }
1993         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
1994             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
1995         }
1996         plogd("registerForIncomingDatagram: callback=" + callback);
1997         return mDatagramController.registerForSatelliteDatagram(subId, callback);
1998     }
1999 
2000     /**
2001      * Unregister to stop receiving incoming datagrams over satellite.
2002      * If callback was not registered before, the request will be ignored.
2003      *
2004      * @param subId The subId of the subscription to unregister for incoming satellite datagrams.
2005      * @param callback The callback that was passed to
2006      *                 {@link #registerForIncomingDatagram(int, ISatelliteDatagramCallback)}.
2007      */
unregisterForIncomingDatagram(int subId, @NonNull ISatelliteDatagramCallback callback)2008     public void unregisterForIncomingDatagram(int subId,
2009             @NonNull ISatelliteDatagramCallback callback) {
2010         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2011             plogd("unregisterForIncomingDatagram: oemEnabledSatelliteFlag is disabled");
2012             return;
2013         }
2014         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
2015             return;
2016         }
2017         plogd("unregisterForIncomingDatagram: callback=" + callback);
2018         mDatagramController.unregisterForSatelliteDatagram(subId, callback);
2019     }
2020 
2021     /**
2022      * Poll pending satellite datagrams over satellite.
2023      *
2024      * This method requests modem to check if there are any pending datagrams to be received over
2025      * satellite. If there are any incoming datagrams, they will be received via
2026      * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived(
2027      * long, SatelliteDatagram, int, Consumer)}
2028      *
2029      * @param subId The subId of the subscription used for receiving datagrams.
2030      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
2031      */
pollPendingDatagrams(int subId, @NonNull IIntegerConsumer callback)2032     public void pollPendingDatagrams(int subId, @NonNull IIntegerConsumer callback) {
2033         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2034         int error = evaluateOemSatelliteRequestAllowed(true);
2035         if (error != SATELLITE_RESULT_SUCCESS) {
2036             result.accept(error);
2037             return;
2038         }
2039 
2040         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
2041         mDatagramController.pollPendingSatelliteDatagrams(validSubId, result);
2042     }
2043 
2044     /**
2045      * Send datagram over satellite.
2046      *
2047      * Gateway encodes SOS message or location sharing message into a datagram and passes it as
2048      * input to this method. Datagram received here will be passed down to modem without any
2049      * encoding or encryption.
2050      *
2051      * @param subId The subId of the subscription to send satellite datagrams for.
2052      * @param datagramType datagram type indicating whether the datagram is of type
2053      *                     SOS_SMS or LOCATION_SHARING.
2054      * @param datagram encoded gateway datagram which is encrypted by the caller.
2055      *                 Datagram will be passed down to modem without any encoding or encryption.
2056      * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
2057      *                                 full screen mode.
2058      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
2059      */
sendDatagram(int subId, @SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull IIntegerConsumer callback)2060     public void sendDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
2061             SatelliteDatagram datagram, boolean needFullScreenPointingUI,
2062             @NonNull IIntegerConsumer callback) {
2063         plogd("sendSatelliteDatagram: subId: " + subId + " datagramType: " + datagramType
2064                 + " needFullScreenPointingUI: " + needFullScreenPointingUI);
2065 
2066         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2067         int error = evaluateOemSatelliteRequestAllowed(true);
2068         if (error != SATELLITE_RESULT_SUCCESS) {
2069             result.accept(error);
2070             return;
2071         }
2072 
2073         /**
2074          * TODO for NTN-based satellites: Check if satellite is acquired.
2075          */
2076         if (mNeedsSatellitePointing) {
2077 
2078             mPointingAppController.startPointingUI(needFullScreenPointingUI, mIsDemoModeEnabled,
2079                     mIsEmergency);
2080         }
2081 
2082         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
2083         mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram,
2084                 needFullScreenPointingUI, result);
2085     }
2086 
2087     /**
2088      * Request to get the time after which the satellite will be visible.
2089      *
2090      * @param subId The subId to get the time after which the satellite will be visible for.
2091      * @param result The result receiver that returns the time after which the satellite will
2092      *               be visible if the request is successful or an error code if the request failed.
2093      */
requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result)2094     public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) {
2095         int error = evaluateOemSatelliteRequestAllowed(true);
2096         if (error != SATELLITE_RESULT_SUCCESS) {
2097             result.send(error, null);
2098             return;
2099         }
2100 
2101         sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, null);
2102     }
2103 
2104     /**
2105      * Inform whether the device is aligned with satellite for demo mode.
2106      *
2107      * @param subId The subId of the subscription.
2108      * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}.
2109      */
setDeviceAlignedWithSatellite(@onNull int subId, @NonNull boolean isAligned)2110     public void setDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) {
2111         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2112             plogd("setDeviceAlignedWithSatellite: oemEnabledSatelliteFlag is disabled");
2113             return;
2114         }
2115 
2116         DemoSimulator.getInstance().setDeviceAlignedWithSatellite(isAligned);
2117         mDatagramController.setDeviceAlignedWithSatellite(isAligned);
2118     }
2119 
2120     /**
2121      * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
2122      * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled,
2123      * and request modem to enable/disable satellite accordingly if the desired state does not match
2124      * the current state.
2125      *
2126      * @param subId The subId of the subscription to request for.
2127      * @param reason Reason for disallowing satellite communication for carrier.
2128      * @param callback The callback to get the result of the request.
2129      */
addAttachRestrictionForCarrier(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, @NonNull IIntegerConsumer callback)2130     public void addAttachRestrictionForCarrier(int subId,
2131             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
2132             @NonNull IIntegerConsumer callback) {
2133         if (DBG) logd("addAttachRestrictionForCarrier(" + subId + ", " + reason + ")");
2134         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2135         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2136             result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
2137             logd("addAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is "
2138                     + "disabled");
2139             return;
2140         }
2141 
2142         synchronized (mIsSatelliteEnabledLock) {
2143             if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault(
2144                     subId, Collections.emptySet()).isEmpty()) {
2145                 mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>());
2146             } else if (mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
2147                 result.accept(SATELLITE_RESULT_SUCCESS);
2148                 return;
2149             }
2150             mSatelliteAttachRestrictionForCarrierArray.get(subId).add(reason);
2151         }
2152         RequestHandleSatelliteAttachRestrictionForCarrierArgument request =
2153                 new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason,
2154                         result);
2155         sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request,
2156                 SatelliteServiceUtils.getPhone(subId));
2157     }
2158 
2159     /**
2160      * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
2161      * by modem. After updating restriction list, evaluate if satellite should be enabled/disabled,
2162      * and request modem to enable/disable satellite accordingly if the desired state does not match
2163      * the current state.
2164      *
2165      * @param subId The subId of the subscription to request for.
2166      * @param reason Reason for disallowing satellite communication.
2167      * @param callback The callback to get the result of the request.
2168      */
removeAttachRestrictionForCarrier(int subId, @SatelliteManager.SatelliteCommunicationRestrictionReason int reason, @NonNull IIntegerConsumer callback)2169     public void removeAttachRestrictionForCarrier(int subId,
2170             @SatelliteManager.SatelliteCommunicationRestrictionReason int reason,
2171             @NonNull IIntegerConsumer callback) {
2172         if (DBG) logd("removeAttachRestrictionForCarrier(" + subId + ", " + reason + ")");
2173         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
2174         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2175             result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
2176             logd("removeAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is "
2177                     + "disabled");
2178             return;
2179         }
2180 
2181         synchronized (mIsSatelliteEnabledLock) {
2182             if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault(
2183                     subId, Collections.emptySet()).isEmpty()
2184                     || !mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
2185                 result.accept(SATELLITE_RESULT_SUCCESS);
2186                 return;
2187             }
2188             mSatelliteAttachRestrictionForCarrierArray.get(subId).remove(reason);
2189         }
2190         RequestHandleSatelliteAttachRestrictionForCarrierArgument request =
2191                 new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId, reason,
2192                         result);
2193         sendRequestAsync(CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE, request,
2194                 SatelliteServiceUtils.getPhone(subId));
2195     }
2196 
2197     /**
2198      * Get reasons for disallowing satellite communication, as requested by
2199      * {@link #addAttachRestrictionForCarrier(int, int, IIntegerConsumer)}.
2200      *
2201      * @param subId The subId of the subscription to request for.
2202      *
2203      * @return Set of reasons for disallowing satellite attach for carrier.
2204      */
getAttachRestrictionReasonsForCarrier(int subId)2205     @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
2206         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2207             logd("getAttachRestrictionReasonsForCarrier: carrierEnabledSatelliteFlag is "
2208                     + "disabled");
2209             return new HashSet<>();
2210         }
2211         synchronized (mIsSatelliteEnabledLock) {
2212             Set<Integer> resultSet =
2213                     mSatelliteAttachRestrictionForCarrierArray.get(subId);
2214             if (resultSet == null) {
2215                 return new HashSet<>();
2216             }
2217             return new HashSet<>(resultSet);
2218         }
2219     }
2220 
2221     /**
2222      * Request to get the signal strength of the satellite connection.
2223      *
2224      * @param subId The subId of the subscription to request for.
2225      * @param result Result receiver to get the error code of the request and the current signal
2226      * strength of the satellite connection.
2227      */
requestNtnSignalStrength(int subId, @NonNull ResultReceiver result)2228     public void requestNtnSignalStrength(int subId, @NonNull ResultReceiver result) {
2229         if (DBG) plogd("requestNtnSignalStrength()");
2230 
2231         int error = evaluateOemSatelliteRequestAllowed(true);
2232         if (error != SATELLITE_RESULT_SUCCESS) {
2233             result.send(error, null);
2234             return;
2235         }
2236 
2237         /* In case cache is available, it is not needed to request non-terrestrial signal strength
2238         to modem */
2239         synchronized (mNtnSignalsStrengthLock) {
2240             if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
2241                 Bundle bundle = new Bundle();
2242                 bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, mNtnSignalStrength);
2243                 result.send(SATELLITE_RESULT_SUCCESS, bundle);
2244                 return;
2245             }
2246         }
2247 
2248         Phone phone = SatelliteServiceUtils.getPhone();
2249         sendRequestAsync(CMD_REQUEST_NTN_SIGNAL_STRENGTH, result, phone);
2250     }
2251 
2252     /**
2253      * Registers for NTN signal strength changed from satellite modem. If the registration operation
2254      * is not successful, a {@link ServiceSpecificException} that contains
2255      * {@link SatelliteManager.SatelliteResult} will be thrown.
2256      *
2257      * @param subId The id of the subscription to request for.
2258      * @param callback The callback to handle the NTN signal strength changed event. If the
2259      * operation is successful, {@link INtnSignalStrengthCallback#onNtnSignalStrengthChanged(
2260      * NtnSignalStrength)} will return an instance of {@link NtnSignalStrength} with a value of
2261      * {@link NtnSignalStrength.NtnSignalStrengthLevel} when the signal strength of non-terrestrial
2262      * network has changed.
2263      *
2264      * @throws ServiceSpecificException If the callback registration operation fails.
2265      */
registerForNtnSignalStrengthChanged(int subId, @NonNull INtnSignalStrengthCallback callback)2266     public void registerForNtnSignalStrengthChanged(int subId,
2267             @NonNull INtnSignalStrengthCallback callback) throws RemoteException {
2268         if (DBG) plogd("registerForNtnSignalStrengthChanged()");
2269 
2270         int error = evaluateOemSatelliteRequestAllowed(true);
2271         if (error == SATELLITE_RESULT_SUCCESS) {
2272             mNtnSignalStrengthChangedListeners.put(callback.asBinder(), callback);
2273             synchronized (mNtnSignalsStrengthLock) {
2274                 try {
2275                     callback.onNtnSignalStrengthChanged(mNtnSignalStrength);
2276                     plogd("registerForNtnSignalStrengthChanged: " + mNtnSignalStrength);
2277                 } catch (RemoteException ex) {
2278                     ploge("registerForNtnSignalStrengthChanged: RemoteException ex="
2279                             + ex);
2280                 }
2281             }
2282         } else {
2283             throw new RemoteException(new IllegalStateException("registration fails: " + error));
2284         }
2285     }
2286 
2287     /**
2288      * Unregisters for NTN signal strength changed from satellite modem.
2289      * If callback was not registered before, the request will be ignored.
2290      *
2291      * @param subId The id of the subscription to unregister for listening NTN signal strength
2292      * changed event.
2293      * @param callback The callback that was passed to
2294      * {@link #registerForNtnSignalStrengthChanged(int, INtnSignalStrengthCallback)}
2295      */
unregisterForNtnSignalStrengthChanged( int subId, @NonNull INtnSignalStrengthCallback callback)2296     public void unregisterForNtnSignalStrengthChanged(
2297             int subId, @NonNull INtnSignalStrengthCallback callback) {
2298         if (DBG) plogd("unregisterForNtnSignalStrengthChanged()");
2299 
2300         int error = evaluateOemSatelliteRequestAllowed(true);
2301         if (error == SATELLITE_RESULT_SUCCESS) {
2302             mNtnSignalStrengthChangedListeners.remove(callback.asBinder());
2303         }
2304     }
2305 
2306     /**
2307      * Registers for satellite capabilities change event from the satellite service.
2308      *
2309      * @param subId The id of the subscription to request for.
2310      * @param callback The callback to handle the satellite capabilities changed event.
2311      *
2312      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
2313      */
registerForCapabilitiesChanged( int subId, @NonNull ISatelliteCapabilitiesCallback callback)2314     @SatelliteManager.SatelliteResult public int registerForCapabilitiesChanged(
2315             int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
2316         if (DBG) plogd("registerForCapabilitiesChanged()");
2317 
2318         int error = evaluateOemSatelliteRequestAllowed(true);
2319         if (error != SATELLITE_RESULT_SUCCESS) return error;
2320 
2321         mSatelliteCapabilitiesChangedListeners.put(callback.asBinder(), callback);
2322         return SATELLITE_RESULT_SUCCESS;
2323     }
2324 
2325     /**
2326      * Unregisters for satellite capabilities change event from the satellite service.
2327      * If callback was not registered before, the request will be ignored.
2328      *
2329      * @param subId The id of the subscription to unregister for listening satellite capabilities
2330      * changed event.
2331      * @param callback The callback that was passed to
2332      * {@link #registerForCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)}
2333      */
unregisterForCapabilitiesChanged( int subId, @NonNull ISatelliteCapabilitiesCallback callback)2334     public void unregisterForCapabilitiesChanged(
2335             int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
2336         if (DBG) plogd("unregisterForCapabilitiesChanged()");
2337 
2338         int error = evaluateOemSatelliteRequestAllowed(true);
2339         if (error == SATELLITE_RESULT_SUCCESS) {
2340             mSatelliteCapabilitiesChangedListeners.remove(callback.asBinder());
2341         }
2342     }
2343 
2344     /**
2345      * Registers for the satellite supported state changed.
2346      *
2347      * @param subId The subId of the subscription to register for supported state changed.
2348      * @param callback The callback to handle the satellite supported state changed event.
2349      *
2350      * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
2351      */
registerForSatelliteSupportedStateChanged( int subId, @NonNull ISatelliteSupportedStateCallback callback)2352     @SatelliteManager.SatelliteResult public int registerForSatelliteSupportedStateChanged(
2353             int subId, @NonNull ISatelliteSupportedStateCallback callback) {
2354         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2355             plogd("registerForSatelliteSupportedStateChanged: oemEnabledSatelliteFlag is disabled");
2356             return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
2357         }
2358 
2359         mSatelliteSupportedStateChangedListeners.put(callback.asBinder(), callback);
2360         return SATELLITE_RESULT_SUCCESS;
2361     }
2362 
2363     /**
2364      * Unregisters for the satellite supported state changed.
2365      * If callback was not registered before, the request will be ignored.
2366      *
2367      * @param subId The subId of the subscription to unregister for supported state changed.
2368      * @param callback The callback that was passed to
2369      * {@link #registerForSatelliteSupportedStateChanged(int, ISatelliteSupportedStateCallback)}.
2370      */
unregisterForSatelliteSupportedStateChanged( int subId, @NonNull ISatelliteSupportedStateCallback callback)2371     public void unregisterForSatelliteSupportedStateChanged(
2372             int subId, @NonNull ISatelliteSupportedStateCallback callback) {
2373         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2374             plogd("unregisterForSatelliteSupportedStateChanged: "
2375                     + "oemEnabledSatelliteFlag is disabled");
2376             return;
2377         }
2378         mSatelliteSupportedStateChangedListeners.remove(callback.asBinder());
2379     }
2380 
2381     /**
2382      * This API can be used by only CTS to update satellite vendor service package name.
2383      *
2384      * @param servicePackageName The package name of the satellite vendor service.
2385      * @return {@code true} if the satellite vendor service is set successfully,
2386      * {@code false} otherwise.
2387      */
setSatelliteServicePackageName(@ullable String servicePackageName)2388     public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) {
2389         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2390             plogd("setSatelliteServicePackageName: oemEnabledSatelliteFlag is disabled");
2391             return false;
2392         }
2393         if (!isMockModemAllowed()) {
2394             plogd("setSatelliteServicePackageName: mock modem not allowed");
2395             return false;
2396         }
2397 
2398         // Cached states need to be cleared whenever switching satellite vendor services.
2399         plogd("setSatelliteServicePackageName: Resetting cached states");
2400         synchronized (mIsSatelliteSupportedLock) {
2401             mIsSatelliteSupported = null;
2402         }
2403         synchronized (mSatelliteViaOemProvisionLock) {
2404             mIsSatelliteViaOemProvisioned = null;
2405         }
2406         synchronized (mIsSatelliteEnabledLock) {
2407             mIsSatelliteEnabled = null;
2408         }
2409         synchronized (mSatelliteCapabilitiesLock) {
2410             mSatelliteCapabilities = null;
2411         }
2412         mSatelliteModemInterface.setSatelliteServicePackageName(servicePackageName);
2413         return true;
2414     }
2415 
2416     /**
2417      * This API can be used by only CTS to update the timeout duration in milliseconds that
2418      * satellite should stay at listening mode to wait for the next incoming page before disabling
2419      * listening mode.
2420      *
2421      * @param timeoutMillis The timeout duration in millisecond.
2422      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
2423      */
setSatelliteListeningTimeoutDuration(long timeoutMillis)2424     public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) {
2425         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2426             plogd("setSatelliteListeningTimeoutDuration: oemEnabledSatelliteFlag is disabled");
2427             return false;
2428         }
2429         if (mSatelliteSessionController == null) {
2430             ploge("mSatelliteSessionController is not initialized yet");
2431             return false;
2432         }
2433         return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis);
2434     }
2435 
2436     /**
2437      * This API can be used by only CTS to override timeout durations used by DatagramController
2438      * module.
2439      *
2440      * @param timeoutMillis The timeout duration in millisecond.
2441      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
2442      */
setDatagramControllerTimeoutDuration( boolean reset, int timeoutType, long timeoutMillis)2443     public boolean setDatagramControllerTimeoutDuration(
2444             boolean reset, int timeoutType, long timeoutMillis) {
2445         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2446             plogd("setDatagramControllerTimeoutDuration: oemEnabledSatelliteFlag is disabled");
2447             return false;
2448         }
2449         plogd("setDatagramControllerTimeoutDuration: reset=" + reset + ", timeoutType="
2450                 + timeoutType + ", timeoutMillis=" + timeoutMillis);
2451         return mDatagramController.setDatagramControllerTimeoutDuration(
2452                 reset, timeoutType, timeoutMillis);
2453     }
2454 
2455     /**
2456      * This API can be used by only CTS to override the boolean configs used by the
2457      * DatagramController module.
2458      *
2459      * @param enable Whether to enable or disable boolean config.
2460      * @return {@code true} if the boolean config is set successfully, {@code false} otherwise.
2461      */
setDatagramControllerBooleanConfig( boolean reset, int booleanType, boolean enable)2462     public boolean setDatagramControllerBooleanConfig(
2463             boolean reset, int booleanType, boolean enable) {
2464         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2465             logd("setDatagramControllerBooleanConfig: oemEnabledSatelliteFlag is disabled");
2466             return false;
2467         }
2468         logd("setDatagramControllerBooleanConfig: reset=" + reset + ", booleanType="
2469                 + booleanType + ", enable=" + enable);
2470         return mDatagramController.setDatagramControllerBooleanConfig(
2471                 reset, booleanType, enable);
2472     }
2473 
2474     /**
2475      * This API can be used by only CTS to override timeout durations used by SatelliteController
2476      * module.
2477      *
2478      * @param timeoutMillis The timeout duration in millisecond.
2479      * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise.
2480      */
setSatelliteControllerTimeoutDuration( boolean reset, int timeoutType, long timeoutMillis)2481     public boolean setSatelliteControllerTimeoutDuration(
2482             boolean reset, int timeoutType, long timeoutMillis) {
2483         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2484             plogd("setSatelliteControllerTimeoutDuration: oemEnabledSatelliteFlag is disabled");
2485             return false;
2486         }
2487         if (!isMockModemAllowed()) {
2488             plogd("setSatelliteControllerTimeoutDuration: mock modem is not allowed");
2489             return false;
2490         }
2491         plogd("setSatelliteControllerTimeoutDuration: reset=" + reset + ", timeoutType="
2492                 + timeoutType + ", timeoutMillis=" + timeoutMillis);
2493         if (timeoutType == TIMEOUT_TYPE_WAIT_FOR_SATELLITE_ENABLING_RESPONSE) {
2494             if (reset) {
2495                 mWaitTimeForSatelliteEnablingResponse =
2496                         getWaitForSatelliteEnablingResponseTimeoutMillis();
2497             } else {
2498                 mWaitTimeForSatelliteEnablingResponse = timeoutMillis;
2499             }
2500             plogd("mWaitTimeForSatelliteEnablingResponse=" + mWaitTimeForSatelliteEnablingResponse);
2501         } else if (timeoutType == TIMEOUT_TYPE_DEMO_POINTING_ALIGNED_DURATION_MILLIS) {
2502             if (reset) {
2503                 mDemoPointingAlignedDurationMillis =
2504                         getDemoPointingAlignedDurationMillisFromResources();
2505             } else {
2506                 mDemoPointingAlignedDurationMillis = timeoutMillis;
2507             }
2508         } else if (timeoutType == TIMEOUT_TYPE_DEMO_POINTING_NOT_ALIGNED_DURATION_MILLIS) {
2509             if (reset) {
2510                 mDemoPointingNotAlignedDurationMillis =
2511                         getDemoPointingNotAlignedDurationMillisFromResources();
2512             } else {
2513                 mDemoPointingNotAlignedDurationMillis = timeoutMillis;
2514             }
2515         } else {
2516             plogw("Invalid timeoutType=" + timeoutType);
2517             return false;
2518         }
2519         return true;
2520     }
2521 
2522     /**
2523      * This API can be used by only CTS to update satellite gateway service package name.
2524      *
2525      * @param servicePackageName The package name of the satellite gateway service.
2526      * @return {@code true} if the satellite gateway service is set successfully,
2527      * {@code false} otherwise.
2528      */
setSatelliteGatewayServicePackageName(@ullable String servicePackageName)2529     public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) {
2530         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2531             plogd("setSatelliteGatewayServicePackageName: oemEnabledSatelliteFlag is disabled");
2532             return false;
2533         }
2534         if (mSatelliteSessionController == null) {
2535             ploge("mSatelliteSessionController is not initialized yet");
2536             return false;
2537         }
2538         return mSatelliteSessionController.setSatelliteGatewayServicePackageName(
2539                 servicePackageName);
2540     }
2541 
2542     /**
2543      * This API can be used by only CTS to update satellite pointing UI app package and class names.
2544      *
2545      * @param packageName The package name of the satellite pointing UI app.
2546      * @param className The class name of the satellite pointing UI app.
2547      * @return {@code true} if the satellite pointing UI app package and class is set successfully,
2548      * {@code false} otherwise.
2549      */
setSatellitePointingUiClassName( @ullable String packageName, @Nullable String className)2550     public boolean setSatellitePointingUiClassName(
2551             @Nullable String packageName, @Nullable String className) {
2552         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2553             plogd("setSatellitePointingUiClassName: oemEnabledSatelliteFlag is disabled");
2554             return false;
2555         }
2556         return mPointingAppController.setSatellitePointingUiClassName(packageName, className);
2557     }
2558 
2559     /**
2560      * This API can be used in only testing to override connectivity status in monitoring emergency
2561      * calls and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
2562      *
2563      * @param handoverType The type of handover from emergency call to satellite messaging. Use one
2564      *                     of the following values to enable the override:
2565      *                     0 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
2566      *                     1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911
2567      *                     To disable the override, use -1 for handoverType.
2568      * @param delaySeconds The event EVENT_DISPLAY_EMERGENCY_MESSAGE will be sent to Dialer
2569      *                     delaySeconds after the emergency call starts.
2570      * @return {@code true} if the handover type is set successfully, {@code false} otherwise.
2571      */
setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds)2572     public boolean setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds) {
2573         if (!isMockModemAllowed()) {
2574             ploge("setEmergencyCallToSatelliteHandoverType: mock modem not allowed");
2575             return false;
2576         }
2577         if (isHandoverTypeValid(handoverType)) {
2578             mEnforcedEmergencyCallToSatelliteHandoverType = handoverType;
2579             mDelayInSendingEventDisplayEmergencyMessage = delaySeconds > 0 ? delaySeconds : 0;
2580         } else {
2581             mEnforcedEmergencyCallToSatelliteHandoverType =
2582                     INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
2583             mDelayInSendingEventDisplayEmergencyMessage = 0;
2584         }
2585         return true;
2586     }
2587 
2588     /**
2589      * This API can be used in only testing to override oem-enabled satellite provision status.
2590      *
2591      * @param reset {@code true} mean the overriding status should not be used, {@code false}
2592      *              otherwise.
2593      * @param isProvisioned The overriding provision status.
2594      * @return {@code true} if the provision status is set successfully, {@code false} otherwise.
2595      */
setOemEnabledSatelliteProvisionStatus(boolean reset, boolean isProvisioned)2596     public boolean setOemEnabledSatelliteProvisionStatus(boolean reset, boolean isProvisioned) {
2597         if (!isMockModemAllowed()) {
2598             ploge("setOemEnabledSatelliteProvisionStatus: mock modem not allowed");
2599             return false;
2600         }
2601         synchronized (mSatelliteViaOemProvisionLock) {
2602             if (reset) {
2603                 mOverriddenIsSatelliteViaOemProvisioned = null;
2604             } else {
2605                 mOverriddenIsSatelliteViaOemProvisioned = isProvisioned;
2606             }
2607         }
2608         return true;
2609     }
2610 
2611     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getEnforcedEmergencyCallToSatelliteHandoverType()2612     protected int getEnforcedEmergencyCallToSatelliteHandoverType() {
2613         return mEnforcedEmergencyCallToSatelliteHandoverType;
2614     }
2615 
2616     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDelayInSendingEventDisplayEmergencyMessage()2617     protected int getDelayInSendingEventDisplayEmergencyMessage() {
2618         return mDelayInSendingEventDisplayEmergencyMessage;
2619     }
2620 
isHandoverTypeValid(int handoverType)2621     private boolean isHandoverTypeValid(int handoverType) {
2622         if (handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
2623                 || handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911) {
2624             return true;
2625         }
2626         return false;
2627     }
2628 
2629     /**
2630      * This function is used by {@link SatelliteModemInterface} to notify
2631      * {@link SatelliteController} that the satellite vendor service was just connected.
2632      * <p>
2633      * {@link SatelliteController} will send requests to satellite modem to check whether it support
2634      * satellite and whether it is provisioned. {@link SatelliteController} will use these cached
2635      * values to serve requests from its clients.
2636      * <p>
2637      * Because satellite vendor service might have just come back from a crash, we need to disable
2638      * the satellite modem so that resources will be cleaned up and internal states will be reset.
2639      */
2640     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
onSatelliteServiceConnected()2641     public void onSatelliteServiceConnected() {
2642         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2643             plogd("onSatelliteServiceConnected: oemEnabledSatelliteFlag is disabled");
2644             return;
2645         }
2646         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
2647             synchronized (mIsSatelliteSupportedLock) {
2648                 if (mIsSatelliteSupported == null) {
2649                     ResultReceiver receiver = new ResultReceiver(this) {
2650                         @Override
2651                         protected void onReceiveResult(
2652                                 int resultCode, Bundle resultData) {
2653                             plogd("onSatelliteServiceConnected.requestIsSatelliteSupported:"
2654                                     + " resultCode=" + resultCode);
2655                         }
2656                     };
2657                     requestIsSatelliteSupported(
2658                             SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver);
2659                 }
2660             }
2661         } else {
2662             plogd("onSatelliteServiceConnected: Satellite vendor service is not supported."
2663                     + " Ignored the event");
2664         }
2665     }
2666 
2667     /**
2668      * This function is used by {@link com.android.internal.telephony.ServiceStateTracker} to notify
2669      * {@link SatelliteController} that it has received a request to power off the cellular radio
2670      * modem. {@link SatelliteController} will then power off the satellite modem.
2671      */
onCellularRadioPowerOffRequested()2672     public void onCellularRadioPowerOffRequested() {
2673         logd("onCellularRadioPowerOffRequested()");
2674         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2675             plogd("onCellularRadioPowerOffRequested: oemEnabledSatelliteFlag is disabled");
2676             return;
2677         }
2678 
2679         synchronized (mIsRadioOnLock) {
2680             mIsRadioOn = false;
2681         }
2682         requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
2683                 false /* enableSatellite */, false /* enableDemoMode */, false /* isEmergency */,
2684                 new IIntegerConsumer.Stub() {
2685                     @Override
2686                     public void accept(int result) {
2687                         plogd("onRadioPowerOffRequested: requestSatelliteEnabled result=" + result);
2688                     }
2689                 });
2690     }
2691 
2692     /**
2693      * @return {@code true} if satellite is supported via OEM on the device,
2694      * {@code  false} otherwise.
2695      */
isSatelliteSupportedViaOem()2696     public boolean isSatelliteSupportedViaOem() {
2697         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2698             plogd("isSatelliteSupported: oemEnabledSatelliteFlag is disabled");
2699             return false;
2700         }
2701         Boolean supported = isSatelliteSupportedViaOemInternal();
2702         return (supported != null ? supported : false);
2703     }
2704 
2705     /**
2706      * @param subId Subscription ID.
2707      * @return The list of satellite PLMNs used for connecting to satellite networks.
2708      */
2709     @NonNull
getSatellitePlmnsForCarrier(int subId)2710     public List<String> getSatellitePlmnsForCarrier(int subId) {
2711         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2712             logd("getSatellitePlmnsForCarrier: carrierEnabledSatelliteFlag is disabled");
2713             return new ArrayList<>();
2714         }
2715 
2716         if (!isSatelliteSupportedViaCarrier(subId)) {
2717             logd("Satellite for carrier is not supported.");
2718             return new ArrayList<>();
2719         }
2720 
2721         synchronized (mSupportedSatelliteServicesLock) {
2722             return mMergedPlmnListPerCarrier.get(subId, new ArrayList<>()).stream().toList();
2723         }
2724     }
2725 
2726     /**
2727      * @param subId Subscription ID.
2728      * @param plmn The satellite plmn.
2729      * @return The list of services supported by the carrier associated with the {@code subId} for
2730      * the satellite network {@code plmn}.
2731      */
2732     @NonNull
getSupportedSatelliteServices(int subId, String plmn)2733     public List<Integer> getSupportedSatelliteServices(int subId, String plmn) {
2734         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2735             logd("getSupportedSatelliteServices: carrierEnabledSatelliteFlag is disabled");
2736             return new ArrayList<>();
2737         }
2738         synchronized (mSupportedSatelliteServicesLock) {
2739             if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) {
2740                 Map<String, Set<Integer>> supportedServices =
2741                         mSatelliteServicesSupportedByCarriers.get(subId);
2742                 if (supportedServices != null && supportedServices.containsKey(plmn)) {
2743                     return new ArrayList<>(supportedServices.get(plmn));
2744                 } else {
2745                     loge("getSupportedSatelliteServices: subId=" + subId + ", supportedServices "
2746                             + "does not contain key plmn=" + plmn);
2747                 }
2748             } else {
2749                 loge("getSupportedSatelliteServices: mSatelliteServicesSupportedByCarriers does "
2750                         + "not contain key subId=" + subId);
2751             }
2752 
2753             /* Returns default capabilities when carrier config does not contain service
2754                capabilities for the given plmn */
2755             PersistableBundle config = getPersistableBundle(subId);
2756             int [] defaultCapabilities = config.getIntArray(
2757                     KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY);
2758             if (defaultCapabilities == null) {
2759                 logd("getSupportedSatelliteServices: defaultCapabilities is null");
2760                 return new ArrayList<>();
2761             }
2762             List<Integer> capabilitiesList = Arrays.stream(
2763                     defaultCapabilities).boxed().collect(Collectors.toList());
2764             logd("getSupportedSatelliteServices: subId=" + subId
2765                     + ", supportedServices does not contain key plmn=" + plmn
2766                     + ", return default values " + capabilitiesList);
2767             return capabilitiesList;
2768         }
2769     }
2770 
2771     /**
2772      * Check whether satellite modem has to attach to a satellite network before sending/receiving
2773      * datagrams.
2774      *
2775      * @return {@code true} if satellite attach is required, {@code false} otherwise.
2776      */
isSatelliteAttachRequired()2777     public boolean isSatelliteAttachRequired() {
2778         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2779             plogd("isSatelliteAttachRequired: oemEnabledSatelliteFlag is disabled");
2780             return false;
2781         }
2782 
2783         synchronized (mSatelliteCapabilitiesLock) {
2784             if (mSatelliteCapabilities == null) {
2785                 ploge("isSatelliteAttachRequired: mSatelliteCapabilities is null");
2786                 return false;
2787             }
2788             if (mSatelliteCapabilities.getSupportedRadioTechnologies().contains(
2789                     SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN)) {
2790                 return true;
2791             }
2792             return false;
2793         }
2794     }
2795 
2796     /**
2797      * @return {@code true} if satellite is supported via carrier by any subscription on the device,
2798      * {@code false} otherwise.
2799      */
isSatelliteSupportedViaCarrier()2800     public boolean isSatelliteSupportedViaCarrier() {
2801         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2802             logd("isSatelliteSupportedViaCarrier: carrierEnabledSatelliteFlag is disabled");
2803             return false;
2804         }
2805         for (Phone phone : PhoneFactory.getPhones()) {
2806             if (isSatelliteSupportedViaCarrier(phone.getSubId())) {
2807                 return true;
2808             }
2809         }
2810         return false;
2811     }
2812 
2813     /**
2814      * @return {@code true} if satellite emergency messaging is supported via carrier by any
2815      * subscription on the device, {@code false} otherwise.
2816      */
isSatelliteEmergencyMessagingSupportedViaCarrier()2817     public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
2818         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2819             logd("isSatelliteEmergencyMessagingSupportedViaCarrier: carrierEnabledSatelliteFlag is"
2820                     + " disabled");
2821             return false;
2822         }
2823         for (Phone phone : PhoneFactory.getPhones()) {
2824             if (isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
2825                 return true;
2826             }
2827         }
2828         return false;
2829     }
2830 
isSatelliteEmergencyMessagingSupportedViaCarrier(int subId)2831     private boolean isSatelliteEmergencyMessagingSupportedViaCarrier(int subId) {
2832         if (!isSatelliteSupportedViaCarrier(subId)) {
2833             return false;
2834         }
2835         PersistableBundle config = getPersistableBundle(subId);
2836         return config.getBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL);
2837     }
2838 
2839     /**
2840      * @return {@code Pair<true, subscription ID>} if any subscription on the device is connected to
2841      * satellite, {@code Pair<false, null>} otherwise.
2842      */
isUsingNonTerrestrialNetworkViaCarrier()2843     private Pair<Boolean, Integer> isUsingNonTerrestrialNetworkViaCarrier() {
2844         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2845             logd("isUsingNonTerrestrialNetwork: carrierEnabledSatelliteFlag is disabled");
2846             return new Pair<>(false, null);
2847         }
2848         for (Phone phone : PhoneFactory.getPhones()) {
2849             ServiceState serviceState = phone.getServiceState();
2850             if (serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) {
2851                 return new Pair<>(true, phone.getSubId());
2852             }
2853         }
2854         return new Pair<>(false, null);
2855     }
2856 
2857     /**
2858      * @return {@code true} if the device is connected to satellite via any carrier within the
2859      * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
2860      * duration, {@code false} otherwise.
2861      */
isSatelliteConnectedViaCarrierWithinHysteresisTime()2862     public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() {
2863         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2864             logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: carrierEnabledSatelliteFlag"
2865                     + " is disabled");
2866             return false;
2867         }
2868         if (isUsingNonTerrestrialNetworkViaCarrier().first) {
2869             return true;
2870         }
2871         for (Phone phone : PhoneFactory.getPhones()) {
2872             if (isInSatelliteModeForCarrierRoaming(phone)) {
2873                 logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: "
2874                         + "subId:" + phone.getSubId()
2875                         + " is connected to satellite within hysteresis time");
2876                 return true;
2877             }
2878         }
2879         return false;
2880     }
2881 
2882     /**
2883      * Get whether device is connected to satellite via carrier.
2884      *
2885      * @param phone phone object
2886      * @return {@code true} if the device is connected to satellite using the phone within the
2887      * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
2888      * duration, {@code false} otherwise.
2889      */
isInSatelliteModeForCarrierRoaming(@ullable Phone phone)2890     public boolean isInSatelliteModeForCarrierRoaming(@Nullable Phone phone) {
2891         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2892             logd("isInSatelliteModeForCarrierRoaming: carrierEnabledSatelliteFlag is disabled");
2893             return false;
2894         }
2895 
2896         if (phone == null) {
2897             return false;
2898         }
2899 
2900         int subId = phone.getSubId();
2901         if (!isSatelliteSupportedViaCarrier(subId)) {
2902             return false;
2903         }
2904 
2905         ServiceState serviceState = phone.getServiceState();
2906         if (serviceState == null) {
2907             return false;
2908         }
2909 
2910         if (serviceState.isUsingNonTerrestrialNetwork()) {
2911             return true;
2912         }
2913 
2914         if (getWwanIsInService(serviceState)) {
2915             // Device is connected to terrestrial network which has coverage
2916             resetCarrierRoamingSatelliteModeParams(subId);
2917             return false;
2918         }
2919 
2920         synchronized (mSatelliteConnectedLock) {
2921             Long lastDisconnectedTime = mLastSatelliteDisconnectedTimesMillis.get(subId);
2922             long satelliteConnectionHysteresisTime =
2923                     getSatelliteConnectionHysteresisTimeMillis(subId);
2924             if (lastDisconnectedTime != null
2925                     && (getElapsedRealtime() - lastDisconnectedTime)
2926                     <= satelliteConnectionHysteresisTime) {
2927                 logd("isInSatelliteModeForCarrierRoaming: " + "subId:" + subId
2928                         + " is connected to satellite within hysteresis time");
2929                 return true;
2930             } else {
2931                 resetCarrierRoamingSatelliteModeParams(subId);
2932                 return false;
2933             }
2934         }
2935     }
2936 
2937     /**
2938      * Return capabilities of carrier roaming satellite network.
2939      *
2940      * @param phone phone object
2941      * @return The list of services supported by the carrier associated with the {@code subId}
2942      */
2943     @NonNull
getCapabilitiesForCarrierRoamingSatelliteMode(Phone phone)2944     public List<Integer> getCapabilitiesForCarrierRoamingSatelliteMode(Phone phone) {
2945         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
2946             logd("getCapabilitiesForCarrierRoamingSatelliteMode: carrierEnabledSatelliteFlag"
2947                     + " is disabled");
2948             return new ArrayList<>();
2949         }
2950 
2951         synchronized (mSatelliteConnectedLock) {
2952             int subId = phone.getSubId();
2953             if (mSatModeCapabilitiesForCarrierRoaming.containsKey(subId)) {
2954                 return mSatModeCapabilitiesForCarrierRoaming.get(subId);
2955             }
2956         }
2957 
2958         return new ArrayList<>();
2959     }
2960 
2961     /**
2962      * Request to get the {@link SatelliteSessionStats} of the satellite service.
2963      *
2964      * @param subId The subId of the subscription to the satellite session stats for.
2965      * @param result The result receiver that returns the {@link SatelliteSessionStats}
2966      *               if the request is successful or an error code if the request failed.
2967      */
requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result)2968     public void requestSatelliteSessionStats(int subId, @NonNull ResultReceiver result) {
2969         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
2970             return;
2971         }
2972         mSessionMetricsStats.requestSatelliteSessionStats(subId, result);
2973     }
2974 
2975     /**
2976      * Get the carrier-enabled emergency call wait for connection timeout millis
2977      */
getCarrierEmergencyCallWaitForConnectionTimeoutMillis()2978     public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
2979         long maxTimeoutMillis = 0;
2980         for (Phone phone : PhoneFactory.getPhones()) {
2981             if (!isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
2982                 continue;
2983             }
2984 
2985             int timeoutMillis =
2986                     getCarrierEmergencyCallWaitForConnectionTimeoutMillis(phone.getSubId());
2987             // Prioritize getting the timeout duration from the phone that is in satellite mode
2988             // with carrier roaming
2989             if (isInSatelliteModeForCarrierRoaming(phone)) {
2990                 return timeoutMillis;
2991             }
2992             if (maxTimeoutMillis < timeoutMillis) {
2993                 maxTimeoutMillis = timeoutMillis;
2994             }
2995         }
2996         if (maxTimeoutMillis != 0) {
2997             return maxTimeoutMillis;
2998         }
2999         return DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
3000     }
3001 
getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId)3002     private int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
3003         PersistableBundle config = getPersistableBundle(subId);
3004         return config.getInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
3005     }
3006 
3007     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
getElapsedRealtime()3008     protected long getElapsedRealtime() {
3009         return SystemClock.elapsedRealtime();
3010     }
3011 
3012     /**
3013      * Register the handler for SIM Refresh notifications.
3014      * @param handler Handler for notification message.
3015      * @param what User-defined message code.
3016      */
registerIccRefresh(Handler handler, int what)3017     public void registerIccRefresh(Handler handler, int what) {
3018         for (Phone phone : PhoneFactory.getPhones()) {
3019             CommandsInterface ci = phone.mCi;
3020             ci.registerForIccRefresh(handler, what, null);
3021         }
3022     }
3023 
3024     /**
3025      * Unregister the handler for SIM Refresh notifications.
3026      * @param handler Handler for notification message.
3027      */
unRegisterIccRefresh(Handler handler)3028     public void unRegisterIccRefresh(Handler handler) {
3029         for (Phone phone : PhoneFactory.getPhones()) {
3030             CommandsInterface ci = phone.mCi;
3031             ci.unregisterForIccRefresh(handler);
3032         }
3033     }
3034 
3035     /**
3036      * To use the satellite service, update the EntitlementStatus and the PlmnAllowedList after
3037      * receiving the satellite configuration from the entitlement server. If satellite
3038      * entitlement is enabled, enable satellite for the carrier. Otherwise, disable satellite.
3039      *
3040      * @param subId              subId
3041      * @param entitlementEnabled {@code true} Satellite service enabled
3042      * @param allowedPlmnList    plmn allowed list to use the satellite service
3043      * @param barredPlmnList    plmn barred list to pass the modem
3044      * @param callback           callback for accept
3045      */
onSatelliteEntitlementStatusUpdated(int subId, boolean entitlementEnabled, @Nullable List<String> allowedPlmnList, @Nullable List<String> barredPlmnList, @Nullable IIntegerConsumer callback)3046     public void onSatelliteEntitlementStatusUpdated(int subId, boolean entitlementEnabled,
3047             @Nullable List<String> allowedPlmnList, @Nullable List<String> barredPlmnList,
3048             @Nullable IIntegerConsumer callback) {
3049         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
3050             logd("onSatelliteEntitlementStatusUpdated: carrierEnabledSatelliteFlag is not enabled");
3051             return;
3052         }
3053 
3054         if (callback == null) {
3055             callback = new IIntegerConsumer.Stub() {
3056                 @Override
3057                 public void accept(int result) {
3058                     logd("updateSatelliteEntitlementStatus:" + result);
3059                 }
3060             };
3061         }
3062         if (allowedPlmnList == null) {
3063             allowedPlmnList = new ArrayList<>();
3064         }
3065         if (barredPlmnList == null) {
3066             barredPlmnList = new ArrayList<>();
3067         }
3068         logd("onSatelliteEntitlementStatusUpdated subId=" + subId + ", entitlementEnabled="
3069                 + entitlementEnabled + ", allowedPlmnList=["
3070                 + String.join(",", allowedPlmnList) + "]" + ", barredPlmnList=["
3071                 + String.join(",", barredPlmnList) + "]");
3072 
3073         synchronized (mSupportedSatelliteServicesLock) {
3074             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false) != entitlementEnabled) {
3075                 logd("update the carrier satellite enabled to " + entitlementEnabled);
3076                 mSatelliteEntitlementStatusPerCarrier.put(subId, entitlementEnabled);
3077                 try {
3078                     mSubscriptionManagerService.setSubscriptionProperty(subId,
3079                             SATELLITE_ENTITLEMENT_STATUS, entitlementEnabled ? "1" : "0");
3080                 } catch (IllegalArgumentException | SecurityException e) {
3081                     loge("onSatelliteEntitlementStatusUpdated: setSubscriptionProperty, e=" + e);
3082                 }
3083             }
3084 
3085             if (isValidPlmnList(allowedPlmnList) && isValidPlmnList(barredPlmnList)) {
3086                 mMergedPlmnListPerCarrier.remove(subId);
3087                 mEntitlementPlmnListPerCarrier.put(subId, allowedPlmnList);
3088                 mEntitlementBarredPlmnListPerCarrier.put(subId, barredPlmnList);
3089                 updatePlmnListPerCarrier(subId);
3090                 configureSatellitePlmnForCarrier(subId);
3091                 mSubscriptionManagerService.setSatelliteEntitlementPlmnList(subId, allowedPlmnList);
3092             } else {
3093                 loge("onSatelliteEntitlementStatusUpdated: either invalid allowedPlmnList "
3094                         + "or invalid barredPlmnList");
3095             }
3096 
3097             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false)) {
3098                 removeAttachRestrictionForCarrier(subId,
3099                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
3100             } else {
3101                 addAttachRestrictionForCarrier(subId,
3102                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
3103             }
3104         }
3105     }
3106 
3107     /**
3108      * A list of PLMNs is considered valid if either the list is empty or all PLMNs in the list
3109      * are valid.
3110      */
isValidPlmnList(@onNull List<String> plmnList)3111     private boolean isValidPlmnList(@NonNull List<String> plmnList) {
3112         for (String plmn : plmnList) {
3113             if (!TelephonyUtils.isValidPlmn(plmn)) {
3114                 ploge("Invalid PLMN = " + plmn);
3115                 return false;
3116             }
3117         }
3118         return true;
3119     }
3120 
3121     /**
3122      * If we have not successfully queried the satellite modem for its satellite service support,
3123      * we will retry the query one more time. Otherwise, we will return the cached result.
3124      */
isSatelliteSupportedViaOemInternal()3125     private Boolean isSatelliteSupportedViaOemInternal() {
3126         synchronized (mIsSatelliteSupportedLock) {
3127             if (mIsSatelliteSupported != null) {
3128                 /* We have already successfully queried the satellite modem. */
3129                 return mIsSatelliteSupported;
3130             }
3131         }
3132         /**
3133          * We have not successfully checked whether the modem supports satellite service.
3134          * Thus, we need to retry it now.
3135          */
3136         requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3137                 new ResultReceiver(this) {
3138                     @Override
3139                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3140                         plogd("isSatelliteSupportedViaOemInternal.requestIsSatelliteSupported:"
3141                                 + " resultCode=" + resultCode);
3142                     }
3143                 });
3144         return null;
3145     }
3146 
handleEventProvisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteResult int result)3147     private void handleEventProvisionSatelliteServiceDone(
3148             @NonNull ProvisionSatelliteServiceArgument arg,
3149             @SatelliteManager.SatelliteResult int result) {
3150         plogd("handleEventProvisionSatelliteServiceDone: result="
3151                 + result + ", subId=" + arg.subId);
3152 
3153         Consumer<Integer> callback = mSatelliteProvisionCallbacks.remove(arg.subId);
3154         if (callback == null) {
3155             ploge("handleEventProvisionSatelliteServiceDone: callback is null for subId="
3156                     + arg.subId);
3157             mProvisionMetricsStats
3158                     .setResultCode(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE)
3159                     .setIsProvisionRequest(true)
3160                     .reportProvisionMetrics();
3161             mControllerMetricsStats.reportProvisionCount(
3162                     SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
3163             return;
3164         }
3165         if (result == SATELLITE_RESULT_SUCCESS
3166                 || result == SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
3167             persistOemEnabledSatelliteProvisionStatus(true);
3168             synchronized (mSatelliteViaOemProvisionLock) {
3169                 mIsSatelliteViaOemProvisioned = true;
3170             }
3171             callback.accept(SATELLITE_RESULT_SUCCESS);
3172             handleEventSatelliteProvisionStateChanged(true);
3173         } else {
3174             callback.accept(result);
3175         }
3176         mProvisionMetricsStats.setResultCode(result)
3177                 .setIsProvisionRequest(true)
3178                 .reportProvisionMetrics();
3179         mControllerMetricsStats.reportProvisionCount(result);
3180     }
3181 
handleEventDeprovisionSatelliteServiceDone( @onNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteResult int result)3182     private void handleEventDeprovisionSatelliteServiceDone(
3183             @NonNull ProvisionSatelliteServiceArgument arg,
3184             @SatelliteManager.SatelliteResult int result) {
3185         if (arg == null) {
3186             ploge("handleEventDeprovisionSatelliteServiceDone: arg is null");
3187             return;
3188         }
3189         plogd("handleEventDeprovisionSatelliteServiceDone: result="
3190                 + result + ", subId=" + arg.subId);
3191 
3192         if (result == SATELLITE_RESULT_SUCCESS
3193                 || result == SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
3194             persistOemEnabledSatelliteProvisionStatus(false);
3195             synchronized (mSatelliteViaOemProvisionLock) {
3196                 mIsSatelliteViaOemProvisioned = false;
3197             }
3198             if (arg.callback != null) {
3199                 arg.callback.accept(SATELLITE_RESULT_SUCCESS);
3200             }
3201             handleEventSatelliteProvisionStateChanged(false);
3202         } else if (arg.callback != null) {
3203             arg.callback.accept(result);
3204         }
3205         mProvisionMetricsStats.setResultCode(result)
3206                 .setIsProvisionRequest(false)
3207                 .reportProvisionMetrics();
3208         mControllerMetricsStats.reportDeprovisionCount(result);
3209     }
3210 
handleStartSatelliteTransmissionUpdatesDone(@onNull AsyncResult ar)3211     private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) {
3212         SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj;
3213         SatelliteTransmissionUpdateArgument arg =
3214                 (SatelliteTransmissionUpdateArgument) request.argument;
3215         int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
3216                 "handleStartSatelliteTransmissionUpdatesDone");
3217         arg.errorCallback.accept(errorCode);
3218 
3219         if (errorCode != SATELLITE_RESULT_SUCCESS) {
3220             mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
3221             // We need to remove the callback from our listener list since the caller might not call
3222             // stopSatelliteTransmissionUpdates to unregister the callback in case of failure.
3223             mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId,
3224                     arg.errorCallback, arg.callback);
3225         } else {
3226             mPointingAppController.setStartedSatelliteTransmissionUpdates(true);
3227         }
3228     }
3229 
3230     /**
3231      * Posts the specified command to be executed on the main thread and returns immediately.
3232      *
3233      * @param command command to be executed on the main thread
3234      * @param argument additional parameters required to perform of the operation
3235      * @param phone phone object used to perform the operation.
3236      */
sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone)3237     private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) {
3238         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
3239                 argument, phone);
3240         Message msg = this.obtainMessage(command, request);
3241         msg.sendToTarget();
3242     }
3243 
3244     /**
3245      * Posts the specified command to be executed on the main thread. As this is a synchronous
3246      * request, it waits until the request is complete and then return the result.
3247      *
3248      * @param command command to be executed on the main thread
3249      * @param argument additional parameters required to perform of the operation
3250      * @param phone phone object used to perform the operation.
3251      * @return result of the operation
3252      */
sendRequest(int command, @NonNull Object argument, @Nullable Phone phone)3253     private @Nullable Object sendRequest(int command, @NonNull Object argument,
3254             @Nullable Phone phone) {
3255         if (Looper.myLooper() == this.getLooper()) {
3256             throw new RuntimeException("This method will deadlock if called from the main thread");
3257         }
3258 
3259         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
3260                 argument, phone);
3261         Message msg = this.obtainMessage(command, request);
3262         msg.sendToTarget();
3263 
3264         synchronized (request) {
3265             while(request.result == null) {
3266                 try {
3267                     request.wait();
3268                 } catch (InterruptedException e) {
3269                     // Do nothing, go back and wait until the request is complete.
3270                 }
3271             }
3272         }
3273         return request.result;
3274     }
3275 
3276     /**
3277      * Check if satellite is provisioned for a subscription on the device.
3278      * @return true if satellite is provisioned on the given subscription else return false.
3279      */
3280     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
3281     @Nullable
isSatelliteViaOemProvisioned()3282     protected Boolean isSatelliteViaOemProvisioned() {
3283         synchronized (mSatelliteViaOemProvisionLock) {
3284             if (mOverriddenIsSatelliteViaOemProvisioned != null) {
3285                 return mOverriddenIsSatelliteViaOemProvisioned;
3286             }
3287 
3288             if (mIsSatelliteViaOemProvisioned != null) {
3289                 return mIsSatelliteViaOemProvisioned;
3290             }
3291         }
3292 
3293         requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3294                 new ResultReceiver(this) {
3295                     @Override
3296                     protected void onReceiveResult(int resultCode, Bundle resultData) {
3297                         plogd("isSatelliteViaOemProvisioned: resultCode=" + resultCode);
3298                     }
3299                 });
3300         return null;
3301     }
3302 
handleSatelliteEnabled(SatelliteControllerHandlerRequest request)3303     private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) {
3304         RequestSatelliteEnabledArgument argument =
3305                 (RequestSatelliteEnabledArgument) request.argument;
3306         handlePersistentLoggingOnSessionStart(argument);
3307         if (mSatelliteSessionController != null) {
3308             mSatelliteSessionController.onSatelliteEnablementStarted(argument.enableSatellite);
3309         } else {
3310             ploge("handleSatelliteEnabled: mSatelliteSessionController is not initialized yet");
3311         }
3312 
3313         if (!argument.enableSatellite && mSatelliteModemInterface.isSatelliteServiceSupported()) {
3314             synchronized (mIsSatelliteEnabledLock) {
3315                 mWaitingForDisableSatelliteModemResponse = true;
3316                 mWaitingForSatelliteModemOff = true;
3317             }
3318         }
3319 
3320         Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request);
3321         mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
3322                 argument.enableDemoMode, argument.isEmergency, onCompleted);
3323         startWaitForSatelliteEnablingResponseTimer(argument);
3324         // Logs satellite session timestamps for session metrics
3325         if (argument.enableSatellite) {
3326             mSessionStartTimeStamp = System.currentTimeMillis();
3327         }
3328         mSessionProcessingTimeStamp = System.currentTimeMillis();
3329     }
3330 
handleRequestSatelliteAttachRestrictionForCarrierCmd( SatelliteControllerHandlerRequest request)3331     private void handleRequestSatelliteAttachRestrictionForCarrierCmd(
3332             SatelliteControllerHandlerRequest request) {
3333         RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
3334                 (RequestHandleSatelliteAttachRestrictionForCarrierArgument) request.argument;
3335 
3336         if (argument.reason == SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER) {
3337             if (!persistSatelliteAttachEnabledForCarrierSetting(argument.subId)) {
3338                 argument.callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
3339                 return;
3340             }
3341         }
3342 
3343         evaluateEnablingSatelliteForCarrier(argument.subId, argument.reason, argument.callback);
3344     }
3345 
updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported)3346     private void updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported) {
3347         synchronized (mIsSatelliteSupportedLock) {
3348             mIsSatelliteSupported = supported;
3349         }
3350         mSatelliteSessionController = SatelliteSessionController.make(
3351                 mContext, getLooper(), mFeatureFlags, supported);
3352         plogd("create a new SatelliteSessionController due to isSatelliteSupported state has "
3353                 + "changed to " + supported);
3354 
3355         if (supported) {
3356             registerForSatelliteProvisionStateChanged();
3357             registerForPendingDatagramCount();
3358             registerForSatelliteModemStateChanged();
3359             registerForNtnSignalStrengthChanged();
3360             registerForCapabilitiesChanged();
3361 
3362             requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3363                     new ResultReceiver(this) {
3364                         @Override
3365                         protected void onReceiveResult(int resultCode, Bundle resultData) {
3366                             plogd("requestIsSatelliteProvisioned: resultCode=" + resultCode
3367                                     + ", resultData=" + resultData);
3368                             requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3369                                     false, false, false,
3370                                     new IIntegerConsumer.Stub() {
3371                                         @Override
3372                                         public void accept(int result) {
3373                                             plogd("requestSatelliteEnabled: result=" + result);
3374                                         }
3375                                     });
3376                         }
3377                     });
3378             requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3379                     new ResultReceiver(this) {
3380                         @Override
3381                         protected void onReceiveResult(int resultCode, Bundle resultData) {
3382                             plogd("requestSatelliteCapabilities: resultCode=" + resultCode
3383                                     + ", resultData=" + resultData);
3384                         }
3385                     });
3386         }
3387         registerForSatelliteSupportedStateChanged();
3388     }
3389 
updateSatelliteEnabledState(boolean enabled, String caller)3390     private void updateSatelliteEnabledState(boolean enabled, String caller) {
3391         synchronized (mIsSatelliteEnabledLock) {
3392             mIsSatelliteEnabled = enabled;
3393         }
3394         if (mSatelliteSessionController != null) {
3395             mSatelliteSessionController.onSatelliteEnabledStateChanged(enabled);
3396             mSatelliteSessionController.setDemoMode(mIsDemoModeEnabled);
3397         } else {
3398             ploge(caller + ": mSatelliteSessionController is not initialized yet");
3399         }
3400         if (!enabled) {
3401             mIsModemEnabledReportingNtnSignalStrength.set(false);
3402         }
3403     }
3404 
registerForSatelliteProvisionStateChanged()3405     private void registerForSatelliteProvisionStateChanged() {
3406         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3407             if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) {
3408                 mSatelliteModemInterface.registerForSatelliteProvisionStateChanged(
3409                         this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null);
3410                 mRegisteredForProvisionStateChangedWithSatelliteService.set(true);
3411             }
3412         }
3413     }
3414 
registerForPendingDatagramCount()3415     private void registerForPendingDatagramCount() {
3416         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3417             if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) {
3418                 mSatelliteModemInterface.registerForPendingDatagrams(
3419                         this, EVENT_PENDING_DATAGRAMS, null);
3420                 mRegisteredForPendingDatagramCountWithSatelliteService.set(true);
3421             }
3422         }
3423     }
3424 
registerForSatelliteModemStateChanged()3425     private void registerForSatelliteModemStateChanged() {
3426         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3427             if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) {
3428                 mSatelliteModemInterface.registerForSatelliteModemStateChanged(
3429                         this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
3430                 mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true);
3431             }
3432         }
3433     }
3434 
registerForNtnSignalStrengthChanged()3435     private void registerForNtnSignalStrengthChanged() {
3436         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
3437             plogd("registerForNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled");
3438             return;
3439         }
3440 
3441         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3442             if (!mRegisteredForNtnSignalStrengthChanged.get()) {
3443                 mSatelliteModemInterface.registerForNtnSignalStrengthChanged(
3444                         this, EVENT_NTN_SIGNAL_STRENGTH_CHANGED, null);
3445                 mRegisteredForNtnSignalStrengthChanged.set(true);
3446             }
3447         }
3448     }
3449 
registerForCapabilitiesChanged()3450     private void registerForCapabilitiesChanged() {
3451         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
3452             plogd("registerForCapabilitiesChanged: oemEnabledSatelliteFlag is disabled");
3453             return;
3454         }
3455 
3456         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3457             if (!mRegisteredForSatelliteCapabilitiesChanged.get()) {
3458                 mSatelliteModemInterface.registerForSatelliteCapabilitiesChanged(
3459                         this, EVENT_SATELLITE_CAPABILITIES_CHANGED, null);
3460                 mRegisteredForSatelliteCapabilitiesChanged.set(true);
3461             }
3462         }
3463     }
3464 
registerForSatelliteSupportedStateChanged()3465     private void registerForSatelliteSupportedStateChanged() {
3466         if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
3467             if (!mRegisteredForSatelliteSupportedStateChanged.get()) {
3468                 mSatelliteModemInterface.registerForSatelliteSupportedStateChanged(
3469                         this, EVENT_SATELLITE_SUPPORTED_STATE_CHANGED, null);
3470                 mRegisteredForSatelliteSupportedStateChanged.set(true);
3471             }
3472         }
3473     }
3474 
handleEventSatelliteProvisionStateChanged(boolean provisioned)3475     private void handleEventSatelliteProvisionStateChanged(boolean provisioned) {
3476         plogd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned);
3477 
3478         synchronized (mSatelliteViaOemProvisionLock) {
3479             persistOemEnabledSatelliteProvisionStatus(provisioned);
3480             mIsSatelliteViaOemProvisioned = provisioned;
3481         }
3482 
3483         List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>();
3484         mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
3485             try {
3486                 listener.onSatelliteProvisionStateChanged(provisioned);
3487             } catch (RemoteException e) {
3488                 plogd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e);
3489                 deadCallersList.add(listener);
3490             }
3491         });
3492         deadCallersList.forEach(listener -> {
3493             mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
3494         });
3495     }
3496 
handleEventSatelliteModemStateChanged( @atelliteManager.SatelliteModemState int state)3497     private void handleEventSatelliteModemStateChanged(
3498             @SatelliteManager.SatelliteModemState int state) {
3499         plogd("handleEventSatelliteModemStateChanged: state=" + state);
3500         if (state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE
3501                 || state == SatelliteManager.SATELLITE_MODEM_STATE_OFF) {
3502             synchronized (mIsSatelliteEnabledLock) {
3503                 if ((state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE)
3504                         || ((mIsSatelliteEnabled == null || isSatelliteEnabled())
3505                         && !mWaitingForDisableSatelliteModemResponse)) {
3506                     int error = (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF)
3507                             ? SATELLITE_RESULT_SUCCESS
3508                             : SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE;
3509                     Consumer<Integer> callback = null;
3510                     synchronized (mSatelliteEnabledRequestLock) {
3511                         if (mSatelliteEnabledRequest != null) {
3512                             callback = mSatelliteEnabledRequest.callback;
3513                         }
3514                     }
3515                     moveSatelliteToOffStateAndCleanUpResources(error, callback);
3516                 } else {
3517                     plogd("Either waiting for the response of disabling satellite modem or the"
3518                             + " event should be ignored because isSatelliteEnabled="
3519                             + isSatelliteEnabled()
3520                             + ", mIsSatelliteEnabled=" + mIsSatelliteEnabled);
3521                 }
3522                 mWaitingForSatelliteModemOff = false;
3523             }
3524         } else {
3525             if (mSatelliteSessionController != null) {
3526                 mSatelliteSessionController.onSatelliteModemStateChanged(state);
3527             } else {
3528                 ploge("handleEventSatelliteModemStateChanged: mSatelliteSessionController is null");
3529             }
3530         }
3531     }
3532 
handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength)3533     private void handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
3534         logd("handleEventNtnSignalStrengthChanged: ntnSignalStrength=" + ntnSignalStrength);
3535         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
3536             logd("handleEventNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled");
3537             return;
3538         }
3539 
3540         synchronized (mNtnSignalsStrengthLock) {
3541             mNtnSignalStrength = ntnSignalStrength;
3542         }
3543         mSessionMetricsStats.updateMaxNtnSignalStrengthLevel(ntnSignalStrength.getLevel());
3544 
3545         List<INtnSignalStrengthCallback> deadCallersList = new ArrayList<>();
3546         mNtnSignalStrengthChangedListeners.values().forEach(listener -> {
3547             try {
3548                 listener.onNtnSignalStrengthChanged(ntnSignalStrength);
3549             } catch (RemoteException e) {
3550                 plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e);
3551                 deadCallersList.add(listener);
3552             }
3553         });
3554         deadCallersList.forEach(listener -> {
3555             mNtnSignalStrengthChangedListeners.remove(listener.asBinder());
3556         });
3557     }
3558 
handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities)3559     private void handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) {
3560         plogd("handleEventSatelliteCapabilitiesChanged()");
3561         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
3562             plogd("handleEventSatelliteCapabilitiesChanged: oemEnabledSatelliteFlag is disabled");
3563             return;
3564         }
3565 
3566         synchronized (mSatelliteCapabilitiesLock) {
3567             mSatelliteCapabilities = capabilities;
3568         }
3569 
3570         List<ISatelliteCapabilitiesCallback> deadCallersList = new ArrayList<>();
3571         mSatelliteCapabilitiesChangedListeners.values().forEach(listener -> {
3572             try {
3573                 listener.onSatelliteCapabilitiesChanged(capabilities);
3574             } catch (RemoteException e) {
3575                 plogd("handleEventSatelliteCapabilitiesChanged RemoteException: " + e);
3576                 deadCallersList.add(listener);
3577             }
3578         });
3579         deadCallersList.forEach(listener -> {
3580             mSatelliteCapabilitiesChangedListeners.remove(listener.asBinder());
3581         });
3582     }
3583 
handleEventSatelliteSupportedStateChanged(boolean supported)3584     private void handleEventSatelliteSupportedStateChanged(boolean supported) {
3585         plogd("handleSatelliteSupportedStateChangedEvent: supported=" + supported);
3586 
3587         synchronized (mIsSatelliteSupportedLock) {
3588             if (mIsSatelliteSupported != null && mIsSatelliteSupported == supported) {
3589                 if (DBG) {
3590                     plogd("current satellite support state and new supported state are matched,"
3591                             + " ignore update.");
3592                 }
3593                 return;
3594             }
3595 
3596             updateSatelliteSupportedStateWhenSatelliteServiceConnected(supported);
3597 
3598             /* In case satellite has been reported as not support from modem, but satellite is
3599                enabled, request disable satellite. */
3600             synchronized (mIsSatelliteEnabledLock) {
3601                 if (!supported && mIsSatelliteEnabled != null && mIsSatelliteEnabled) {
3602                     plogd("Invoke requestSatelliteEnabled(), supported=false, "
3603                             + "mIsSatelliteEnabled=true");
3604                     requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
3605                             false /* enableSatellite */, false /* enableDemoMode */,
3606                             false /* isEmergency */,
3607                             new IIntegerConsumer.Stub() {
3608                                 @Override
3609                                 public void accept(int result) {
3610                                     plogd("handleSatelliteSupportedStateChangedEvent: request "
3611                                             + "satellite disable, result="
3612                                             + result);
3613                                 }
3614                             });
3615 
3616                 }
3617             }
3618             mIsSatelliteSupported = supported;
3619         }
3620 
3621         List<ISatelliteSupportedStateCallback> deadCallersList = new ArrayList<>();
3622         mSatelliteSupportedStateChangedListeners.values().forEach(listener -> {
3623             try {
3624                 listener.onSatelliteSupportedStateChanged(supported);
3625             } catch (RemoteException e) {
3626                 plogd("handleSatelliteSupportedStateChangedEvent RemoteException: " + e);
3627                 deadCallersList.add(listener);
3628             }
3629         });
3630         deadCallersList.forEach(listener -> {
3631             mSatelliteSupportedStateChangedListeners.remove(listener.asBinder());
3632         });
3633     }
3634 
3635     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSettingsKeyForSatelliteMode(int val)3636     protected void setSettingsKeyForSatelliteMode(int val) {
3637         plogd("setSettingsKeyForSatelliteMode val: " + val);
3638         Settings.Global.putInt(mContext.getContentResolver(),
3639                     Settings.Global.SATELLITE_MODE_ENABLED, val);
3640     }
3641 
3642     /**
3643      * Allow screen rotation temporary in rotation locked foldable device.
3644      * <p>
3645      * Temporarily allow screen rotation user to catch satellite signals properly by UI guide in
3646      * emergency situations. Unlock the setting value so that the screen rotation is not locked, and
3647      * return it to the original value when the satellite service is finished.
3648      * <p>
3649      * Note that, only the unfolded screen will be temporarily allowed screen rotation.
3650      *
3651      * @param val {@link SATELLITE_MODE_ENABLED_TRUE} if satellite mode is enabled,
3652      *     {@link SATELLITE_MODE_ENABLED_FALSE} satellite mode is not enabled.
3653      */
3654     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
setSettingsKeyToAllowDeviceRotation(int val)3655     protected void setSettingsKeyToAllowDeviceRotation(int val) {
3656         // Only allows on a foldable device type.
3657         if (!isFoldable(mContext)) {
3658             return;
3659         }
3660 
3661         switch (val) {
3662             case SATELLITE_MODE_ENABLED_TRUE:
3663                 mDeviceRotationLockToBackupAndRestore =
3664                         Settings.Secure.getString(mContentResolver,
3665                                 Settings.Secure.DEVICE_STATE_ROTATION_LOCK);
3666                 String unlockedRotationSettings = replaceDeviceRotationValue(
3667                         mDeviceRotationLockToBackupAndRestore == null
3668                                 ? "" : mDeviceRotationLockToBackupAndRestore,
3669                         Settings.Secure.DEVICE_STATE_ROTATION_KEY_UNFOLDED,
3670                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCKED);
3671                 Settings.Secure.putString(mContentResolver,
3672                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK, unlockedRotationSettings);
3673                 logd("setSettingsKeyToAllowDeviceRotation(TRUE), RotationSettings is changed"
3674                         + " from " + mDeviceRotationLockToBackupAndRestore
3675                         + " to " + unlockedRotationSettings);
3676                 break;
3677             case SATELLITE_MODE_ENABLED_FALSE:
3678                 if (mDeviceRotationLockToBackupAndRestore == null) {
3679                     break;
3680                 }
3681                 Settings.Secure.putString(mContentResolver,
3682                         Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
3683                         mDeviceRotationLockToBackupAndRestore);
3684                 logd("setSettingsKeyToAllowDeviceRotation(FALSE), RotationSettings is restored to"
3685                         + mDeviceRotationLockToBackupAndRestore);
3686                 mDeviceRotationLockToBackupAndRestore = "";
3687                 break;
3688             default:
3689                 loge("setSettingsKeyToAllowDeviceRotation(" + val + "), never reach here.");
3690                 break;
3691         }
3692     }
3693 
3694     /**
3695      * If the device type is foldable.
3696      *
3697      * @param context context
3698      * @return {@code true} if device type is foldable. {@code false} for otherwise.
3699      */
isFoldable(Context context)3700     private boolean isFoldable(Context context) {
3701         return context.getResources().getIntArray(R.array.config_foldedDeviceStates).length > 0;
3702     }
3703 
3704     /**
3705      * Replaces a value of given a target key with a new value in a string of key-value pairs.
3706      * <p>
3707      * Replaces the value corresponding to the target key with a new value. If the key value is not
3708      * found in the device rotation information, it is not replaced.
3709      *
3710      * @param deviceRotationValue Device rotation key values separated by colon(':').
3711      * @param targetKey The key of the new item caller wants to add.
3712      * @param newValue  The value of the new item caller want to add.
3713      * @return A new string where all the key-value pairs.
3714      */
replaceDeviceRotationValue( @onNull String deviceRotationValue, int targetKey, int newValue)3715     private static String replaceDeviceRotationValue(
3716             @NonNull String deviceRotationValue, int targetKey, int newValue) {
3717         // Use list of Key-Value pair
3718         List<Pair<Integer, Integer>> keyValuePairs = new ArrayList<>();
3719 
3720         String[] pairs = deviceRotationValue.split(":");
3721         if (pairs.length % 2 != 0) {
3722             // Return without modifying. The key-value may be incorrect if length is an odd number.
3723             loge("The length of key-value pair do not match. Return without modification.");
3724             return deviceRotationValue;
3725         }
3726 
3727         // collect into keyValuePairs
3728         for (int i = 0; i < pairs.length; i += 2) {
3729             try {
3730                 int key = Integer.parseInt(pairs[i]);
3731                 int value = Integer.parseInt(pairs[i + 1]);
3732                 keyValuePairs.add(new Pair<>(key, key == targetKey ? newValue : value));
3733             } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
3734                 // Return without modifying if got exception.
3735                 loge("got error while parsing key-value. Return without modification. e:" + e);
3736                 return deviceRotationValue;
3737             }
3738         }
3739 
3740         return keyValuePairs.stream()
3741                 .map(pair -> pair.first + ":" + pair.second) // Convert to "key:value" format
3742                 .collect(Collectors.joining(":")); // Join pairs with colons
3743     }
3744 
3745     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
areAllRadiosDisabled()3746     protected boolean areAllRadiosDisabled() {
3747         synchronized (mRadioStateLock) {
3748             if ((mDisableBTOnSatelliteEnabled && mBTStateEnabled)
3749                     || (mDisableNFCOnSatelliteEnabled && mNfcStateEnabled)
3750                     || (mDisableWifiOnSatelliteEnabled && mWifiStateEnabled)
3751                     || (mDisableUWBOnSatelliteEnabled && mUwbStateEnabled)) {
3752                 plogd("All radios are not disabled yet.");
3753                 return false;
3754             }
3755             plogd("All radios are disabled.");
3756             return true;
3757         }
3758     }
3759 
evaluateToSendSatelliteEnabledSuccess()3760     private void evaluateToSendSatelliteEnabledSuccess() {
3761         plogd("evaluateToSendSatelliteEnabledSuccess");
3762         synchronized (mSatelliteEnabledRequestLock) {
3763             if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null)
3764                     && mWaitingForRadioDisabled) {
3765                 plogd("Sending success to callback that sent enable satellite request");
3766                 mIsEmergency = mSatelliteEnabledRequest.isEmergency;
3767                 synchronized (mIsSatelliteEnabledLock) {
3768                     mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite;
3769                 }
3770                 mSatelliteEnabledRequest.callback.accept(SATELLITE_RESULT_SUCCESS);
3771                 updateSatelliteEnabledState(
3772                         mSatelliteEnabledRequest.enableSatellite,
3773                         "EVENT_SET_SATELLITE_ENABLED_DONE");
3774                 mSatelliteEnabledRequest = null;
3775                 mWaitingForRadioDisabled = false;
3776             }
3777         }
3778     }
3779 
resetSatelliteEnabledRequest()3780     private void resetSatelliteEnabledRequest() {
3781         plogd("resetSatelliteEnabledRequest");
3782         synchronized (mSatelliteEnabledRequestLock) {
3783             mSatelliteEnabledRequest = null;
3784             mWaitingForRadioDisabled = false;
3785         }
3786     }
3787 
moveSatelliteToOffStateAndCleanUpResources( @atelliteManager.SatelliteResult int error, @Nullable Consumer<Integer> callback)3788     private void moveSatelliteToOffStateAndCleanUpResources(
3789             @SatelliteManager.SatelliteResult int error, @Nullable Consumer<Integer> callback) {
3790         plogd("moveSatelliteToOffStateAndCleanUpResources");
3791         synchronized (mIsSatelliteEnabledLock) {
3792             resetSatelliteEnabledRequest();
3793             setDemoModeEnabled(false);
3794             handlePersistentLoggingOnSessionEnd(mIsEmergency);
3795             mIsEmergency = false;
3796             mIsSatelliteEnabled = false;
3797             setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE);
3798             setSettingsKeyToAllowDeviceRotation(SATELLITE_MODE_ENABLED_FALSE);
3799             if (callback != null) callback.accept(error);
3800             updateSatelliteEnabledState(
3801                     false, "moveSatelliteToOffStateAndCleanUpResources");
3802         }
3803     }
3804 
setDemoModeEnabled(boolean enabled)3805     private void setDemoModeEnabled(boolean enabled) {
3806         mIsDemoModeEnabled = enabled;
3807         mDatagramController.setDemoMode(mIsDemoModeEnabled);
3808         plogd("setDemoModeEnabled: mIsDemoModeEnabled=" + mIsDemoModeEnabled);
3809     }
3810 
isMockModemAllowed()3811     private boolean isMockModemAllowed() {
3812         return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false));
3813     }
3814 
configureSatellitePlmnForCarrier(int subId)3815     private void configureSatellitePlmnForCarrier(int subId) {
3816         logd("configureSatellitePlmnForCarrier");
3817         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
3818             logd("configureSatellitePlmnForCarrier: carrierEnabledSatelliteFlag is disabled");
3819             return;
3820         }
3821         synchronized (mSupportedSatelliteServicesLock) {
3822             List<String> carrierPlmnList = mMergedPlmnListPerCarrier.get(subId,
3823                     new ArrayList<>()).stream().toList();
3824             List<String> barredPlmnList = mEntitlementBarredPlmnListPerCarrier.get(subId,
3825                     new ArrayList<>()).stream().toList();
3826             int slotId = SubscriptionManager.getSlotIndex(subId);
3827             mSatelliteModemInterface.setSatellitePlmn(slotId, carrierPlmnList,
3828                     SatelliteServiceUtils.mergeStrLists(
3829                             carrierPlmnList, mSatellitePlmnListFromOverlayConfig, barredPlmnList),
3830                     obtainMessage(EVENT_SET_SATELLITE_PLMN_INFO_DONE));
3831         }
3832     }
3833 
handleSetSatellitePlmnInfoDoneEvent(Message msg)3834     private void handleSetSatellitePlmnInfoDoneEvent(Message msg) {
3835         AsyncResult ar = (AsyncResult) msg.obj;
3836         SatelliteServiceUtils.getSatelliteError(ar, "handleSetSatellitePlmnInfoCmd");
3837     }
3838 
updateSupportedSatelliteServicesForActiveSubscriptions()3839     private void updateSupportedSatelliteServicesForActiveSubscriptions() {
3840         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
3841             logd("updateSupportedSatelliteServicesForActiveSubscriptions: "
3842                     + "carrierEnabledSatelliteFlag is disabled");
3843             return;
3844         }
3845 
3846         synchronized (mSupportedSatelliteServicesLock) {
3847             mSatelliteServicesSupportedByCarriers.clear();
3848             mMergedPlmnListPerCarrier.clear();
3849             int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
3850             if (activeSubIds != null) {
3851                 for (int subId : activeSubIds) {
3852                     updateSupportedSatelliteServices(subId);
3853                 }
3854             } else {
3855                 loge("updateSupportedSatelliteServicesForActiveSubscriptions: "
3856                         + "activeSubIds is null");
3857             }
3858         }
3859     }
3860 
3861     /**
3862      * If the entitlementPlmnList exist then used it.
3863      * Otherwise, If the carrierPlmnList exist then used it.
3864      */
updatePlmnListPerCarrier(int subId)3865     private void updatePlmnListPerCarrier(int subId) {
3866         plogd("updatePlmnListPerCarrier: subId=" + subId);
3867         synchronized (mSupportedSatelliteServicesLock) {
3868             List<String> carrierPlmnList, entitlementPlmnList;
3869             if (getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
3870                     false)) {
3871                 entitlementPlmnList = mEntitlementPlmnListPerCarrier.get(subId,
3872                         new ArrayList<>()).stream().toList();
3873                 plogd("updatePlmnListPerCarrier: entitlementPlmnList="
3874                         + String.join(",", entitlementPlmnList)
3875                         + " size=" + entitlementPlmnList.size());
3876                 if (!entitlementPlmnList.isEmpty()) {
3877                     mMergedPlmnListPerCarrier.put(subId, entitlementPlmnList);
3878                     plogd("mMergedPlmnListPerCarrier is updated by Entitlement");
3879                     mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
3880                             SatelliteConstants.CONFIG_DATA_SOURCE_ENTITLEMENT);
3881                     return;
3882                 }
3883             }
3884 
3885             SatelliteConfig satelliteConfig = getSatelliteConfig();
3886             if (satelliteConfig != null) {
3887                 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
3888                 int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
3889                 List<String> plmnList = satelliteConfig.getAllSatellitePlmnsForCarrier(carrierId);
3890                 if (!plmnList.isEmpty()) {
3891                     plogd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : "
3892                             + String.join(",", plmnList));
3893                     mMergedPlmnListPerCarrier.put(subId, plmnList);
3894                     mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
3895                             SatelliteConstants.CONFIG_DATA_SOURCE_CONFIG_UPDATER);
3896                     return;
3897                 }
3898             }
3899 
3900             if (mSatelliteServicesSupportedByCarriers.containsKey(subId)
3901                     && mSatelliteServicesSupportedByCarriers.get(subId) != null) {
3902                 carrierPlmnList =
3903                         mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList();
3904                 plogd("mMergedPlmnListPerCarrier is updated by carrier config: "
3905                         + String.join(",", carrierPlmnList));
3906                 mCarrierRoamingSatelliteControllerStats.reportConfigDataSource(
3907                         SatelliteConstants.CONFIG_DATA_SOURCE_CARRIER_CONFIG);
3908             } else {
3909                 carrierPlmnList = new ArrayList<>();
3910                 plogd("Empty mMergedPlmnListPerCarrier");
3911             }
3912             mMergedPlmnListPerCarrier.put(subId, carrierPlmnList);
3913         }
3914     }
3915 
updateSupportedSatelliteServices(int subId)3916     private void updateSupportedSatelliteServices(int subId) {
3917         plogd("updateSupportedSatelliteServices with subId " + subId);
3918         synchronized (mSupportedSatelliteServicesLock) {
3919             SatelliteConfig satelliteConfig = getSatelliteConfig();
3920 
3921             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
3922             int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
3923 
3924             if (satelliteConfig != null) {
3925                 Map<String, Set<Integer>> supportedServicesPerPlmn =
3926                         satelliteConfig.getSupportedSatelliteServices(carrierId);
3927                 if (!supportedServicesPerPlmn.isEmpty()) {
3928                     mSatelliteServicesSupportedByCarriers.put(subId, supportedServicesPerPlmn);
3929                     plogd("updateSupportedSatelliteServices using ConfigUpdater, "
3930                             + "supportedServicesPerPlmn = " + supportedServicesPerPlmn.size());
3931                     updatePlmnListPerCarrier(subId);
3932                     return;
3933                 } else {
3934                     plogd("supportedServicesPerPlmn is empty");
3935                 }
3936             }
3937 
3938             mSatelliteServicesSupportedByCarriers.put(
3939                     subId, readSupportedSatelliteServicesFromCarrierConfig(subId));
3940             updatePlmnListPerCarrier(subId);
3941             plogd("updateSupportedSatelliteServices using carrier config");
3942         }
3943     }
3944 
3945     @NonNull
readSatellitePlmnsFromOverlayConfig()3946     private List<String> readSatellitePlmnsFromOverlayConfig() {
3947         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
3948             logd("readSatellitePlmnsFromOverlayConfig: carrierEnabledSatelliteFlag is disabled");
3949             return new ArrayList<>();
3950         }
3951 
3952         String[] devicePlmns = readStringArrayFromOverlayConfig(
3953                 R.array.config_satellite_providers);
3954         return Arrays.stream(devicePlmns).toList();
3955     }
3956 
3957     @NonNull
readSupportedSatelliteServicesFromCarrierConfig(int subId)3958     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) {
3959         PersistableBundle config = getPersistableBundle(subId);
3960         return SatelliteServiceUtils.parseSupportedSatelliteServices(
3961                 config.getPersistableBundle(
3962                         KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
3963     }
3964 
getConfigForSubId(int subId)3965     @NonNull private PersistableBundle getConfigForSubId(int subId) {
3966         PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId,
3967                 KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
3968                 KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
3969                 KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT,
3970                 KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
3971                 KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
3972                 KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
3973                 KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
3974         if (config == null || config.isEmpty()) {
3975             config = CarrierConfigManager.getDefaultConfig();
3976         }
3977         return config;
3978     }
3979 
handleCarrierConfigChanged(int slotIndex, int subId, int carrierId, int specificCarrierId)3980     private void handleCarrierConfigChanged(int slotIndex, int subId, int carrierId,
3981             int specificCarrierId) {
3982         plogd("handleCarrierConfigChanged(): slotIndex(" + slotIndex + "), subId("
3983                 + subId + "), carrierId(" + carrierId + "), specificCarrierId("
3984                 + specificCarrierId + ")");
3985         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
3986             return;
3987         }
3988 
3989         updateCarrierConfig(subId);
3990         updateEntitlementPlmnListPerCarrier(subId);
3991         updateSupportedSatelliteServicesForActiveSubscriptions();
3992         processNewCarrierConfigData(subId);
3993         resetCarrierRoamingSatelliteModeParams(subId);
3994     }
3995 
processNewCarrierConfigData(int subId)3996     private void processNewCarrierConfigData(int subId) {
3997         configureSatellitePlmnForCarrier(subId);
3998         setSatelliteAttachEnabledForCarrierOnSimLoaded(subId);
3999         updateRestrictReasonForEntitlementPerCarrier(subId);
4000     }
4001 
4002     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
updateCarrierConfig(int subId)4003     protected void updateCarrierConfig(int subId) {
4004         synchronized (mCarrierConfigArrayLock) {
4005             mCarrierConfigArray.put(subId, getConfigForSubId(subId));
4006         }
4007     }
4008 
4009     /**
4010      * If there is no cached entitlement plmn list, read it from the db and use it if it is not an
4011      * empty list.
4012      */
updateEntitlementPlmnListPerCarrier(int subId)4013     private void updateEntitlementPlmnListPerCarrier(int subId) {
4014         if (!getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false)) {
4015             plogd("don't support entitlement");
4016             return;
4017         }
4018 
4019         synchronized (mSupportedSatelliteServicesLock) {
4020             if (mEntitlementPlmnListPerCarrier.indexOfKey(subId) < 0) {
4021                 plogd("updateEntitlementPlmnListPerCarrier: no correspondent cache, load from "
4022                         + "persist storage");
4023                 List<String> entitlementPlmnList =
4024                         mSubscriptionManagerService.getSatelliteEntitlementPlmnList(subId);
4025                 if (entitlementPlmnList.isEmpty()) {
4026                     plogd("updateEntitlementPlmnListPerCarrier: read empty list");
4027                     return;
4028                 }
4029                 plogd("updateEntitlementPlmnListPerCarrier: entitlementPlmnList="
4030                         + String.join(",", entitlementPlmnList));
4031                 mEntitlementPlmnListPerCarrier.put(subId, entitlementPlmnList);
4032             }
4033         }
4034     }
4035 
4036     /**
4037      * When a SIM is loaded, we need to check if users has enabled satellite attach for the carrier
4038      * associated with the SIM, and evaluate if satellite should be enabled for the carrier.
4039      *
4040      * @param subId Subscription ID.
4041      */
setSatelliteAttachEnabledForCarrierOnSimLoaded(int subId)4042     private void setSatelliteAttachEnabledForCarrierOnSimLoaded(int subId) {
4043         synchronized (mIsSatelliteEnabledLock) {
4044             if (isSatelliteAttachEnabledForCarrierByUser(subId)
4045                     && !mIsSatelliteAttachEnabledForCarrierArrayPerSub.getOrDefault(subId,
4046                     false)) {
4047                 evaluateEnablingSatelliteForCarrier(subId,
4048                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, null);
4049             }
4050         }
4051     }
4052 
4053     @NonNull
readStringArrayFromOverlayConfig(@rrayRes int id)4054     private String[] readStringArrayFromOverlayConfig(@ArrayRes int id) {
4055         String[] strArray = null;
4056         try {
4057             strArray = mContext.getResources().getStringArray(id);
4058         } catch (Resources.NotFoundException ex) {
4059             ploge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex);
4060         }
4061         if (strArray == null) {
4062             strArray = new String[0];
4063         }
4064         return strArray;
4065     }
4066 
isSatelliteSupportedViaCarrier(int subId)4067     private boolean isSatelliteSupportedViaCarrier(int subId) {
4068         return getConfigForSubId(subId)
4069                 .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
4070     }
4071 
4072     /**
4073      * Check if satellite attach is enabled by user for the carrier associated with the
4074      * {@code subId}.
4075      *
4076      * @param subId Subscription ID.
4077      *
4078      * @return Returns {@code true} if satellite attach for carrier is enabled by user,
4079      * {@code false} otherwise.
4080      */
isSatelliteAttachEnabledForCarrierByUser(int subId)4081     private boolean isSatelliteAttachEnabledForCarrierByUser(int subId) {
4082         synchronized (mIsSatelliteEnabledLock) {
4083             Set<Integer> cachedRestrictionSet =
4084                     mSatelliteAttachRestrictionForCarrierArray.get(subId);
4085             if (cachedRestrictionSet != null) {
4086                 return !cachedRestrictionSet.contains(
4087                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER);
4088             } else {
4089                 plogd("isSatelliteAttachEnabledForCarrierByUser() no correspondent cache, "
4090                         + "load from persist storage");
4091                 try {
4092                     String enabled =
4093                             mSubscriptionManagerService.getSubscriptionProperty(subId,
4094                                     SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
4095                                     mContext.getOpPackageName(), mContext.getAttributionTag());
4096 
4097                     if (enabled == null) {
4098                         ploge("isSatelliteAttachEnabledForCarrierByUser: invalid subId, subId="
4099                                 + subId);
4100                         return false;
4101                     }
4102 
4103                     if (enabled.isEmpty()) {
4104                         ploge("isSatelliteAttachEnabledForCarrierByUser: no data for subId(" + subId
4105                                 + ")");
4106                         return false;
4107                     }
4108 
4109                     synchronized (mIsSatelliteEnabledLock) {
4110                         boolean result = enabled.equals("1");
4111                         if (!result) {
4112                             mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>());
4113                             mSatelliteAttachRestrictionForCarrierArray.get(subId).add(
4114                                     SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER);
4115                         }
4116                         return result;
4117                     }
4118                 } catch (IllegalArgumentException | SecurityException ex) {
4119                     ploge("isSatelliteAttachEnabledForCarrierByUser: ex=" + ex);
4120                     return false;
4121                 }
4122             }
4123         }
4124     }
4125 
4126     /**
4127      * Check whether there is any reason to restrict satellite communication for the carrier
4128      * associated with the {@code subId}.
4129      *
4130      * @param subId Subscription ID
4131      * @return {@code true} when there is at least on reason, {@code false} otherwise.
4132      */
hasReasonToRestrictSatelliteCommunicationForCarrier(int subId)4133     private boolean hasReasonToRestrictSatelliteCommunicationForCarrier(int subId) {
4134         synchronized (mIsSatelliteEnabledLock) {
4135             return !mSatelliteAttachRestrictionForCarrierArray
4136                     .getOrDefault(subId, Collections.emptySet()).isEmpty();
4137         }
4138     }
4139 
updateRestrictReasonForEntitlementPerCarrier(int subId)4140     private void updateRestrictReasonForEntitlementPerCarrier(int subId) {
4141         if (!getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false)) {
4142             plogd("don't support entitlement");
4143             return;
4144         }
4145 
4146         IIntegerConsumer callback = new IIntegerConsumer.Stub() {
4147             @Override
4148             public void accept(int result) {
4149                 plogd("updateRestrictReasonForEntitlementPerCarrier:" + result);
4150             }
4151         };
4152         synchronized (mSupportedSatelliteServicesLock) {
4153             if (mSatelliteEntitlementStatusPerCarrier.indexOfKey(subId) < 0) {
4154                 plogd("updateRestrictReasonForEntitlementPerCarrier: no correspondent cache, "
4155                         + "load from persist storage");
4156                 String entitlementStatus = null;
4157                 try {
4158                     entitlementStatus =
4159                             mSubscriptionManagerService.getSubscriptionProperty(subId,
4160                                     SATELLITE_ENTITLEMENT_STATUS, mContext.getOpPackageName(),
4161                                     mContext.getAttributionTag());
4162                 } catch (IllegalArgumentException | SecurityException e) {
4163                     ploge("updateRestrictReasonForEntitlementPerCarrier, e=" + e);
4164                 }
4165 
4166                 if (entitlementStatus == null) {
4167                     ploge("updateRestrictReasonForEntitlementPerCarrier: invalid subId, subId="
4168                             + subId + " set to default value");
4169                     entitlementStatus = "0";
4170                 }
4171 
4172                 if (entitlementStatus.isEmpty()) {
4173                     ploge("updateRestrictReasonForEntitlementPerCarrier: no data for subId(" + subId
4174                             + "). set to default value");
4175                     entitlementStatus = "0";
4176                 }
4177                 boolean result = entitlementStatus.equals("1");
4178                 mSatelliteEntitlementStatusPerCarrier.put(subId, result);
4179             }
4180 
4181             if (!mSatelliteEntitlementStatusPerCarrier.get(subId, false)) {
4182                 addAttachRestrictionForCarrier(subId,
4183                         SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT, callback);
4184             }
4185         }
4186     }
4187 
4188     /**
4189      * Save user setting for enabling satellite attach for the carrier associated with the
4190      * {@code subId} to persistent storage.
4191      *
4192      * @param subId Subscription ID.
4193      *
4194      * @return {@code true} if persist successful, {@code false} otherwise.
4195      */
4196     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
persistSatelliteAttachEnabledForCarrierSetting(int subId)4197     protected boolean persistSatelliteAttachEnabledForCarrierSetting(int subId) {
4198         plogd("persistSatelliteAttachEnabledForCarrierSetting");
4199         if (!isValidSubscriptionId(subId)) {
4200             ploge("persistSatelliteAttachEnabledForCarrierSetting: subId is not valid,"
4201                     + " subId=" + subId);
4202             return false;
4203         }
4204 
4205         synchronized (mIsSatelliteEnabledLock) {
4206             try {
4207                 mSubscriptionManagerService.setSubscriptionProperty(subId,
4208                         SATELLITE_ATTACH_ENABLED_FOR_CARRIER,
4209                         mSatelliteAttachRestrictionForCarrierArray.get(subId)
4210                                 .contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)
4211                                 ? "0" : "1");
4212             } catch (IllegalArgumentException | SecurityException ex) {
4213                 ploge("persistSatelliteAttachEnabledForCarrierSetting, ex=" + ex);
4214                 return false;
4215             }
4216         }
4217         return true;
4218     }
4219 
4220     /**
4221      * Evaluate whether satellite attach for carrier should be restricted.
4222      *
4223      * @param subId Subscription Id to evaluate for.
4224      * @return {@code true} satellite attach is restricted, {@code false} otherwise.
4225      */
isSatelliteRestrictedForCarrier(int subId)4226     private boolean isSatelliteRestrictedForCarrier(int subId) {
4227         return !isSatelliteAttachEnabledForCarrierByUser(subId)
4228                 || hasReasonToRestrictSatelliteCommunicationForCarrier(subId);
4229     }
4230 
4231     /**
4232      * Check whether satellite is enabled for carrier at modem.
4233      *
4234      * @param subId Subscription ID to check for.
4235      * @return {@code true} if satellite modem is enabled, {@code false} otherwise.
4236      */
isSatelliteEnabledForCarrierAtModem(int subId)4237     private boolean isSatelliteEnabledForCarrierAtModem(int subId) {
4238         synchronized (mIsSatelliteEnabledLock) {
4239             return mIsSatelliteAttachEnabledForCarrierArrayPerSub.getOrDefault(subId, false);
4240         }
4241     }
4242 
4243     /**
4244      * Evaluate whether satellite modem for carrier should be enabled or not.
4245      * <p>
4246      * Satellite will be enabled only when the following conditions are met:
4247      * <ul>
4248      * <li>Users want to enable it.</li>
4249      * <li>There is no satellite communication restriction, which is added by
4250      * {@link #addAttachRestrictionForCarrier(int, int, IIntegerConsumer)}</li>
4251      * <li>The carrier config {@link
4252      * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
4253      * {@code true}.</li>
4254      * </ul>
4255      *
4256      * @param subId Subscription Id for evaluate for.
4257      * @param callback The callback for getting the result of enabling satellite.
4258      */
evaluateEnablingSatelliteForCarrier(int subId, int reason, @Nullable Consumer<Integer> callback)4259     private void evaluateEnablingSatelliteForCarrier(int subId, int reason,
4260             @Nullable Consumer<Integer> callback) {
4261         if (callback == null) {
4262             callback = errorCode -> plogd("evaluateEnablingSatelliteForCarrier: "
4263                     + "SetSatelliteAttachEnableForCarrier error code =" + errorCode);
4264         }
4265 
4266         if (!isSatelliteSupportedViaCarrier(subId)) {
4267             plogd("Satellite for carrier is not supported. Only user setting is stored");
4268             callback.accept(SATELLITE_RESULT_SUCCESS);
4269             return;
4270         }
4271 
4272         /* Request to enable or disable the satellite in the cellular modem only when the desired
4273         state and the current state are different. */
4274         boolean isSatelliteExpectedToBeEnabled = !isSatelliteRestrictedForCarrier(subId);
4275         if (isSatelliteExpectedToBeEnabled != isSatelliteEnabledForCarrierAtModem(subId)) {
4276             if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
4277                 int simSlot = SubscriptionManager.getSlotIndex(subId);
4278                 RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
4279                         new RequestHandleSatelliteAttachRestrictionForCarrierArgument(subId,
4280                                 reason, callback);
4281                 SatelliteControllerHandlerRequest request =
4282                         new SatelliteControllerHandlerRequest(argument,
4283                                 SatelliteServiceUtils.getPhone(subId));
4284                 Message onCompleted = obtainMessage(
4285                         EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE, request);
4286                 mSatelliteModemInterface.requestSetSatelliteEnabledForCarrier(simSlot,
4287                         isSatelliteExpectedToBeEnabled, onCompleted);
4288             } else {
4289                 callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
4290             }
4291         } else {
4292             callback.accept(SATELLITE_RESULT_SUCCESS);
4293         }
4294     }
4295 
evaluateOemSatelliteRequestAllowed( boolean isProvisionRequired)4296     @SatelliteManager.SatelliteResult private int evaluateOemSatelliteRequestAllowed(
4297             boolean isProvisionRequired) {
4298         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
4299             plogd("oemEnabledSatelliteFlag is disabled");
4300             return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
4301         }
4302         if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
4303             plogd("evaluateOemSatelliteRequestAllowed: satellite service is not supported");
4304             return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
4305         }
4306 
4307         Boolean satelliteSupported = isSatelliteSupportedViaOemInternal();
4308         if (satelliteSupported == null) {
4309             plogd("evaluateOemSatelliteRequestAllowed: satelliteSupported is null");
4310             return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
4311         }
4312         if (!satelliteSupported) {
4313             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
4314         }
4315 
4316         if (isProvisionRequired) {
4317             Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
4318             if (satelliteProvisioned == null) {
4319                 plogd("evaluateOemSatelliteRequestAllowed: satelliteProvisioned is null");
4320                 return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
4321             }
4322             if (!satelliteProvisioned) {
4323                 return SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED;
4324             }
4325         }
4326 
4327         return SATELLITE_RESULT_SUCCESS;
4328     }
4329 
4330     /**
4331      * Returns the non-terrestrial network radio technology that the satellite modem currently
4332      * supports. If multiple technologies are available, returns the first supported technology.
4333      */
4334     @VisibleForTesting
getSupportedNtnRadioTechnology()4335     protected @SatelliteManager.NTRadioTechnology int getSupportedNtnRadioTechnology() {
4336         synchronized (mSatelliteCapabilitiesLock) {
4337             if (mSatelliteCapabilities != null) {
4338                 return mSatelliteCapabilities.getSupportedRadioTechnologies()
4339                         .stream().findFirst().orElse(SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN);
4340             }
4341             return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN;
4342         }
4343     }
4344 
sendErrorAndReportSessionMetrics(@atelliteManager.SatelliteResult int error, Consumer<Integer> result)4345     private void sendErrorAndReportSessionMetrics(@SatelliteManager.SatelliteResult int error,
4346             Consumer<Integer> result) {
4347         result.accept(error);
4348         mSessionMetricsStats.setInitializationResult(error)
4349                 .setSatelliteTechnology(getSupportedNtnRadioTechnology())
4350                 .setIsDemoMode(mIsDemoModeEnabled)
4351                 .reportSessionMetrics();
4352         mSessionStartTimeStamp = 0;
4353         mSessionProcessingTimeStamp = 0;
4354     }
4355 
registerForServiceStateChanged()4356     private void registerForServiceStateChanged() {
4357         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
4358             return;
4359         }
4360         for (Phone phone : PhoneFactory.getPhones()) {
4361             phone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
4362         }
4363     }
4364 
handleEventServiceStateChanged()4365     private void handleEventServiceStateChanged() {
4366         handleServiceStateForSatelliteConnectionViaCarrier();
4367         determineSystemNotification();
4368     }
4369 
handleServiceStateForSatelliteConnectionViaCarrier()4370     private void handleServiceStateForSatelliteConnectionViaCarrier() {
4371         for (Phone phone : PhoneFactory.getPhones()) {
4372             int subId = phone.getSubId();
4373             ServiceState serviceState = phone.getServiceState();
4374             if (serviceState == null) {
4375                 continue;
4376             }
4377 
4378             synchronized (mSatelliteConnectedLock) {
4379                 CarrierRoamingSatelliteSessionStats sessionStats =
4380                         mCarrierRoamingSatelliteSessionStatsMap.get(subId);
4381 
4382                 if (serviceState.isUsingNonTerrestrialNetwork()) {
4383                     if (sessionStats != null) {
4384                         sessionStats.onSignalStrength(phone);
4385                         if (!mWasSatelliteConnectedViaCarrier.get(subId)) {
4386                             // Log satellite connection start
4387                             sessionStats.onConnectionStart(phone);
4388                         }
4389                     }
4390 
4391                     resetCarrierRoamingSatelliteModeParams(subId);
4392                     mWasSatelliteConnectedViaCarrier.put(subId, true);
4393 
4394                     for (NetworkRegistrationInfo nri
4395                             : serviceState.getNetworkRegistrationInfoList()) {
4396                         if (nri.isNonTerrestrialNetwork()) {
4397                             mSatModeCapabilitiesForCarrierRoaming.put(subId,
4398                                     nri.getAvailableServices());
4399                         }
4400                     }
4401                 } else {
4402                     Boolean connected = mWasSatelliteConnectedViaCarrier.get(subId);
4403                     if (getWwanIsInService(serviceState)) {
4404                         resetCarrierRoamingSatelliteModeParams(subId);
4405                     } else if (connected != null && connected) {
4406                         // The device just got disconnected from a satellite network
4407                         // and is not connected to any terrestrial network that  has coverage
4408                         mLastSatelliteDisconnectedTimesMillis.put(subId, getElapsedRealtime());
4409 
4410                         plogd("sendMessageDelayed subId:" + subId
4411                                 + " phoneId:" + phone.getPhoneId()
4412                                 + " time:" + getSatelliteConnectionHysteresisTimeMillis(subId));
4413                         sendMessageDelayed(obtainMessage(EVENT_NOTIFY_NTN_HYSTERESIS_TIMED_OUT,
4414                                         phone.getPhoneId()),
4415                                 getSatelliteConnectionHysteresisTimeMillis(subId));
4416 
4417                         if (sessionStats != null) {
4418                             // Log satellite connection end
4419                             sessionStats.onConnectionEnd();
4420                         }
4421                     }
4422                     mWasSatelliteConnectedViaCarrier.put(subId, false);
4423                 }
4424                 updateLastNotifiedNtnModeAndNotify(phone);
4425             }
4426         }
4427     }
4428 
updateLastNotifiedNtnModeAndNotify(@ullable Phone phone)4429     private void updateLastNotifiedNtnModeAndNotify(@Nullable Phone phone) {
4430         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
4431 
4432         if (phone == null) {
4433             return;
4434         }
4435 
4436         int subId = phone.getSubId();
4437         synchronized (mSatelliteConnectedLock) {
4438             boolean initialized = mInitialized.get(subId);
4439             boolean lastNotifiedNtnMode = mLastNotifiedNtnMode.get(subId);
4440             boolean currNtnMode = isInSatelliteModeForCarrierRoaming(phone);
4441             if (!initialized || lastNotifiedNtnMode != currNtnMode) {
4442                 if (!initialized) mInitialized.put(subId, true);
4443                 mLastNotifiedNtnMode.put(subId, currNtnMode);
4444                 phone.notifyCarrierRoamingNtnModeChanged(currNtnMode);
4445                 logCarrierRoamingSatelliteSessionStats(phone, lastNotifiedNtnMode, currNtnMode);
4446             }
4447         }
4448     }
4449 
logCarrierRoamingSatelliteSessionStats(@onNull Phone phone, boolean lastNotifiedNtnMode, boolean currNtnMode)4450     private void logCarrierRoamingSatelliteSessionStats(@NonNull Phone phone,
4451             boolean lastNotifiedNtnMode, boolean currNtnMode) {
4452         synchronized (mSatelliteConnectedLock) {
4453             int subId = phone.getSubId();
4454             if (!lastNotifiedNtnMode && currNtnMode) {
4455                 // Log satellite session start
4456                 CarrierRoamingSatelliteSessionStats sessionStats =
4457                         CarrierRoamingSatelliteSessionStats.getInstance(subId);
4458                 sessionStats.onSessionStart(phone.getCarrierId(), phone);
4459                 mCarrierRoamingSatelliteSessionStatsMap.put(subId, sessionStats);
4460             } else if (lastNotifiedNtnMode && !currNtnMode) {
4461                 // Log satellite session end
4462                 CarrierRoamingSatelliteSessionStats sessionStats =
4463                         mCarrierRoamingSatelliteSessionStatsMap.get(subId);
4464                 sessionStats.onSessionEnd();
4465                 mCarrierRoamingSatelliteSessionStatsMap.remove(subId);
4466             }
4467         }
4468     }
4469 
getSatelliteConnectionHysteresisTimeMillis(int subId)4470     private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
4471         PersistableBundle config = getPersistableBundle(subId);
4472         return (config.getInt(
4473                 KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
4474     }
4475 
persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned)4476     private void persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned) {
4477         synchronized (mSatelliteViaOemProvisionLock) {
4478             plogd("persistOemEnabledSatelliteProvisionStatus: isProvisioned=" + isProvisioned);
4479 
4480             if (!loadSatelliteSharedPreferences()) return;
4481 
4482             if (mSharedPreferences == null) {
4483                 ploge("persistOemEnabledSatelliteProvisionStatus: mSharedPreferences is null");
4484             } else {
4485                 mSharedPreferences.edit().putBoolean(
4486                         OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY, isProvisioned).apply();
4487             }
4488         }
4489     }
4490 
getPersistedOemEnabledSatelliteProvisionStatus()4491     private boolean getPersistedOemEnabledSatelliteProvisionStatus() {
4492         synchronized (mSatelliteViaOemProvisionLock) {
4493             if (!loadSatelliteSharedPreferences()) return false;
4494 
4495             if (mSharedPreferences == null) {
4496                 ploge("getPersistedOemEnabledSatelliteProvisionStatus: mSharedPreferences is null");
4497                 return false;
4498             } else {
4499                 return mSharedPreferences.getBoolean(
4500                         OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY, false);
4501             }
4502         }
4503     }
4504 
loadSatelliteSharedPreferences()4505     private boolean loadSatelliteSharedPreferences() {
4506         if (mSharedPreferences == null) {
4507             try {
4508                 mSharedPreferences =
4509                         mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
4510                                 Context.MODE_PRIVATE);
4511             } catch (Exception e) {
4512                 ploge("loadSatelliteSharedPreferences: Cannot get default "
4513                         + "shared preferences, e=" + e);
4514                 return false;
4515             }
4516         }
4517         return true;
4518     }
4519 
handleIsSatelliteProvisionedDoneEvent(@onNull AsyncResult ar)4520     private void handleIsSatelliteProvisionedDoneEvent(@NonNull AsyncResult ar) {
4521         SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj;
4522         int error = SatelliteServiceUtils.getSatelliteError(
4523                 ar, "handleIsSatelliteProvisionedDoneEvent");
4524         boolean isSatelliteProvisionedInModem = false;
4525         if (error == SATELLITE_RESULT_SUCCESS) {
4526             if (ar.result == null) {
4527                 ploge("handleIsSatelliteProvisionedDoneEvent: result is null");
4528                 error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
4529             } else {
4530                 isSatelliteProvisionedInModem = ((int[]) ar.result)[0] == 1;
4531             }
4532         } else if (error == SATELLITE_RESULT_REQUEST_NOT_SUPPORTED) {
4533             plogd("handleIsSatelliteProvisionedDoneEvent: Modem does not support this request");
4534             isSatelliteProvisionedInModem = true;
4535         }
4536         boolean isSatelliteViaOemProvisioned =
4537                 isSatelliteProvisionedInModem && getPersistedOemEnabledSatelliteProvisionStatus();
4538         plogd("isSatelliteProvisionedInModem=" + isSatelliteProvisionedInModem
4539                 + ", isSatelliteViaOemProvisioned=" + isSatelliteViaOemProvisioned);
4540         Bundle bundle = new Bundle();
4541         bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, isSatelliteViaOemProvisioned);
4542         synchronized (mSatelliteViaOemProvisionLock) {
4543             mIsSatelliteViaOemProvisioned = isSatelliteViaOemProvisioned;
4544         }
4545         ((ResultReceiver) request.argument).send(error, bundle);
4546     }
4547 
getWaitForSatelliteEnablingResponseTimeoutMillis()4548     private long getWaitForSatelliteEnablingResponseTimeoutMillis() {
4549         return mContext.getResources().getInteger(
4550                 R.integer.config_wait_for_satellite_enabling_response_timeout_millis);
4551     }
4552 
startWaitForSatelliteEnablingResponseTimer( @onNull RequestSatelliteEnabledArgument argument)4553     private void startWaitForSatelliteEnablingResponseTimer(
4554             @NonNull RequestSatelliteEnabledArgument argument) {
4555         synchronized (mSatelliteEnabledRequestLock) {
4556             if (hasMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument)) {
4557                 plogd("WaitForSatelliteEnablingResponseTimer of request ID "
4558                         + argument.requestId + " was already started");
4559                 return;
4560             }
4561             plogd("Start timer to wait for response of the satellite enabling request ID="
4562                     + argument.requestId + ", enableSatellite=" + argument.enableSatellite
4563                     + ", mWaitTimeForSatelliteEnablingResponse="
4564                     + mWaitTimeForSatelliteEnablingResponse);
4565             sendMessageDelayed(obtainMessage(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT,
4566                             argument), mWaitTimeForSatelliteEnablingResponse);
4567         }
4568     }
4569 
stopWaitForSatelliteEnablingResponseTimer( @onNull RequestSatelliteEnabledArgument argument)4570     private void stopWaitForSatelliteEnablingResponseTimer(
4571             @NonNull RequestSatelliteEnabledArgument argument) {
4572         synchronized (mSatelliteEnabledRequestLock) {
4573             plogd("Stop timer to wait for response of the satellite enabling request ID="
4574                     + argument.requestId + ", enableSatellite=" + argument.enableSatellite);
4575             removeMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument);
4576         }
4577     }
4578 
shouldProcessEventSetSatelliteEnabledDone( @onNull RequestSatelliteEnabledArgument argument)4579     private boolean shouldProcessEventSetSatelliteEnabledDone(
4580             @NonNull RequestSatelliteEnabledArgument argument) {
4581         synchronized (mSatelliteEnabledRequestLock) {
4582             if (hasMessages(EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT, argument)) {
4583                 return true;
4584             }
4585             return false;
4586         }
4587     }
4588 
handleEventWaitForSatelliteEnablingResponseTimedOut( @onNull RequestSatelliteEnabledArgument argument)4589     private void handleEventWaitForSatelliteEnablingResponseTimedOut(
4590             @NonNull RequestSatelliteEnabledArgument argument) {
4591         plogw("Timed out to wait for response of the satellite enabling request ID="
4592                 + argument.requestId + ", enableSatellite=" + argument.enableSatellite);
4593 
4594         synchronized (mSatelliteEnabledRequestLock) {
4595             if (mSatelliteEnabledRequest != null) {
4596                 if (mSatelliteEnabledRequest.enableSatellite && !argument.enableSatellite
4597                         && mWaitingForRadioDisabled) {
4598                     // Previous mSatelliteEnabledRequest is successful but waiting for
4599                     // all radios to be turned off.
4600                     mSatelliteEnabledRequest.callback.accept(SATELLITE_RESULT_SUCCESS);
4601                     resetSatelliteEnabledRequest();
4602                 } else if (mSatelliteEnabledRequest.requestId == argument.requestId) {
4603                     resetSatelliteEnabledRequest();
4604                 }
4605             }
4606         }
4607         argument.callback.accept(SATELLITE_RESULT_MODEM_TIMEOUT);
4608 
4609         synchronized (mIsSatelliteEnabledLock) {
4610             if (argument.enableSatellite) {
4611                 if (!mWaitingForDisableSatelliteModemResponse && !mWaitingForSatelliteModemOff) {
4612                     resetSatelliteEnabledRequest();
4613                     IIntegerConsumer callback = new IIntegerConsumer.Stub() {
4614                         @Override
4615                         public void accept(int result) {
4616                             plogd("handleEventWaitForSatelliteEnablingResponseTimedOut: "
4617                                     + "disable satellite result=" + result);
4618                         }
4619                     };
4620                     Consumer<Integer> result =
4621                             FunctionalUtils.ignoreRemoteException(callback::accept);
4622                     RequestSatelliteEnabledArgument request = new RequestSatelliteEnabledArgument(
4623                             false, false, false, result);
4624                     synchronized (mSatelliteEnabledRequestLock) {
4625                         mSatelliteEnabledRequest = request;
4626                     }
4627                     sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
4628                 }
4629                 notifyEnablementFailedToSatelliteSessionController();
4630                 mControllerMetricsStats.reportServiceEnablementFailCount();
4631                 mSessionMetricsStats.setInitializationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
4632                         .setSatelliteTechnology(getSupportedNtnRadioTechnology())
4633                         .setInitializationProcessingTime(
4634                                 System.currentTimeMillis() - mSessionProcessingTimeStamp)
4635                         .setIsDemoMode(mIsDemoModeEnabled)
4636                         .reportSessionMetrics();
4637                 mSessionStartTimeStamp = 0;
4638                 mSessionProcessingTimeStamp = 0;
4639             } else {
4640                 /*
4641                  * Unregister Importance Listener for Pointing UI when Satellite is disabled
4642                  */
4643                 synchronized (mNeedsSatellitePointingLock) {
4644                     if (mNeedsSatellitePointing) {
4645                         mPointingAppController.removeListenerForPointingUI();
4646                     }
4647                 }
4648                 moveSatelliteToOffStateAndCleanUpResources(SATELLITE_RESULT_MODEM_TIMEOUT, null);
4649                 mControllerMetricsStats.onSatelliteDisabled();
4650                 mWaitingForDisableSatelliteModemResponse = false;
4651                 mWaitingForSatelliteModemOff = false;
4652                 mSessionMetricsStats.setTerminationResult(SATELLITE_RESULT_MODEM_TIMEOUT)
4653                         .setSatelliteTechnology(getSupportedNtnRadioTechnology())
4654                         .setTerminationProcessingTime(
4655                                 System.currentTimeMillis() - mSessionProcessingTimeStamp)
4656                         .setSessionDurationSec(calculateSessionDurationTimeSec())
4657                         .reportSessionMetrics();
4658                 mSessionStartTimeStamp = 0;
4659                 mSessionProcessingTimeStamp = 0;
4660             }
4661         }
4662     }
4663 
handleCmdUpdateNtnSignalStrengthReporting(boolean shouldReport)4664     private void handleCmdUpdateNtnSignalStrengthReporting(boolean shouldReport) {
4665         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
4666             plogd("handleCmdUpdateNtnSignalStrengthReporting: oemEnabledSatelliteFlag is "
4667                     + "disabled");
4668             return;
4669         }
4670 
4671         if (!isSatelliteEnabled()) {
4672             plogd("handleCmdUpdateNtnSignalStrengthReporting: ignore request, satellite is "
4673                     + "disabled");
4674             return;
4675         }
4676 
4677         mLatestRequestedStateForNtnSignalStrengthReport.set(shouldReport);
4678         if (mIsModemEnabledReportingNtnSignalStrength.get() == shouldReport) {
4679             plogd("handleCmdUpdateNtnSignalStrengthReporting: ignore request. "
4680                     + "mIsModemEnabledReportingNtnSignalStrength="
4681                     + mIsModemEnabledReportingNtnSignalStrength.get());
4682             return;
4683         }
4684 
4685         updateNtnSignalStrengthReporting(shouldReport);
4686     }
4687 
updateNtnSignalStrengthReporting(boolean shouldReport)4688     private void updateNtnSignalStrengthReporting(boolean shouldReport) {
4689         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
4690             plogd("updateNtnSignalStrengthReporting: oemEnabledSatelliteFlag is "
4691                     + "disabled");
4692             return;
4693         }
4694 
4695         SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
4696                 shouldReport, SatelliteServiceUtils.getPhone());
4697         Message onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE,
4698                 request);
4699         if (shouldReport) {
4700             plogd("updateNtnSignalStrengthReporting: startSendingNtnSignalStrength");
4701             mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
4702         } else {
4703             plogd("updateNtnSignalStrengthReporting: stopSendingNtnSignalStrength");
4704             mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted);
4705         }
4706     }
4707 
4708     /**
4709      * This API can be used by only CTS to override the cached value for the device overlay config
4710      * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
4711      * outgoing satellite datagrams should be sent to modem in demo mode.
4712      *
4713      * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
4714      * satellite modem or not.
4715      *
4716      * @return {@code true} if the operation is successful, {@code false} otherwise.
4717      */
setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode)4718     public boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) {
4719         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
4720             plogd("setShouldSendDatagramToModemInDemoMode: oemEnabledSatelliteFlag is disabled");
4721             return false;
4722         }
4723 
4724         if (!isMockModemAllowed()) {
4725             plogd("setShouldSendDatagramToModemInDemoMode: mock modem not allowed.");
4726             return false;
4727         }
4728 
4729         mDatagramController.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
4730         return true;
4731     }
4732 
determineSystemNotification()4733     private void determineSystemNotification() {
4734         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
4735             logd("determineSystemNotification: carrierEnabledSatelliteFlag is disabled");
4736             return;
4737         }
4738 
4739         Pair<Boolean, Integer> isNtn = isUsingNonTerrestrialNetworkViaCarrier();
4740         if (isNtn.first) {
4741             if (mSharedPreferences == null) {
4742                 try {
4743                     mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
4744                             Context.MODE_PRIVATE);
4745                 } catch (Exception e) {
4746                     loge("Cannot get default shared preferences: " + e);
4747                 }
4748             }
4749             if (mSharedPreferences == null) {
4750                 loge("determineSystemNotification: Cannot get default shared preferences");
4751                 return;
4752             }
4753             if (!mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false)) {
4754                 showSatelliteSystemNotification(isNtn.second);
4755                 mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY,
4756                         true).apply();
4757             }
4758         }
4759     }
4760 
showSatelliteSystemNotification(int subId)4761     private void showSatelliteSystemNotification(int subId) {
4762         plogd("showSatelliteSystemNotification");
4763         final NotificationChannel notificationChannel = new NotificationChannel(
4764                 NOTIFICATION_CHANNEL_ID,
4765                 NOTIFICATION_CHANNEL,
4766                 NotificationManager.IMPORTANCE_DEFAULT
4767         );
4768         notificationChannel.setSound(null, null);
4769         NotificationManager notificationManager = mContext.getSystemService(
4770                 NotificationManager.class);
4771         notificationManager.createNotificationChannel(notificationChannel);
4772 
4773         Notification.Builder notificationBuilder = new Notification.Builder(mContext)
4774                 .setContentTitle(mContext.getResources().getString(
4775                         R.string.satellite_notification_title))
4776                 .setContentText(mContext.getResources().getString(
4777                         R.string.satellite_notification_summary))
4778                 .setSmallIcon(R.drawable.ic_android_satellite_24px)
4779                 .setChannelId(NOTIFICATION_CHANNEL_ID)
4780                 .setAutoCancel(true)
4781                 .setColor(mContext.getColor(
4782                         com.android.internal.R.color.system_notification_accent_color))
4783                 .setVisibility(Notification.VISIBILITY_PUBLIC);
4784 
4785         // Add action to invoke message application.
4786         // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
4787         Optional<Intent> nullableIntent = Optional.ofNullable(
4788                         Telephony.Sms.getDefaultSmsPackage(mContext))
4789                 .flatMap(packageName -> {
4790                     PackageManager pm = mContext.getPackageManager();
4791                     return Optional.ofNullable(pm.getLaunchIntentForPackage(packageName));
4792                 });
4793         // If nullableIntent is null, create new Intent for most common way to invoke message app.
4794         Intent finalIntent = nullableIntent.map(intent -> {
4795             // Invoke the home screen of default message application.
4796             intent.setAction(Intent.ACTION_MAIN);
4797             intent.addCategory(Intent.CATEGORY_HOME);
4798             return intent;
4799         }).orElseGet(() -> {
4800             ploge("showSatelliteSystemNotification: no default sms package name, Invoke "
4801                     + "default sms compose window instead");
4802             Intent newIntent = new Intent(Intent.ACTION_VIEW);
4803             newIntent.setData(Uri.parse("sms:"));
4804             return newIntent;
4805         });
4806 
4807         PendingIntent pendingIntentOpenMessage = PendingIntent.getActivity(mContext, 0,
4808                 finalIntent, PendingIntent.FLAG_IMMUTABLE);
4809         Notification.Action actionOpenMessage = new Notification.Action.Builder(0,
4810                 mContext.getResources().getString(R.string.satellite_notification_open_message),
4811                 pendingIntentOpenMessage).build();
4812         notificationBuilder.addAction(actionOpenMessage);
4813 
4814         // Add action to invoke Satellite setting activity in Settings.
4815         Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
4816         intentSatelliteSetting.putExtra("sub_id", subId);
4817         PendingIntent pendingIntentSatelliteSetting = PendingIntent.getActivity(mContext, 0,
4818                 intentSatelliteSetting, PendingIntent.FLAG_IMMUTABLE);
4819 
4820         Notification.Action actionOpenSatelliteSetting = new Notification.Action.Builder(null,
4821                 mContext.getResources().getString(R.string.satellite_notification_how_it_works),
4822                 pendingIntentSatelliteSetting).build();
4823         notificationBuilder.addAction(actionOpenSatelliteSetting);
4824 
4825         notificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
4826                 notificationBuilder.build(), UserHandle.ALL);
4827 
4828         mCarrierRoamingSatelliteControllerStats.reportCountOfSatelliteNotificationDisplayed();
4829     }
4830 
resetCarrierRoamingSatelliteModeParams()4831     private void resetCarrierRoamingSatelliteModeParams() {
4832         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
4833 
4834         for (Phone phone : PhoneFactory.getPhones()) {
4835             resetCarrierRoamingSatelliteModeParams(phone.getSubId());
4836         }
4837     }
4838 
resetCarrierRoamingSatelliteModeParams(int subId)4839     private void resetCarrierRoamingSatelliteModeParams(int subId) {
4840         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
4841 
4842         synchronized (mSatelliteConnectedLock) {
4843             mLastSatelliteDisconnectedTimesMillis.put(subId, null);
4844             mSatModeCapabilitiesForCarrierRoaming.remove(subId);
4845             mWasSatelliteConnectedViaCarrier.put(subId, false);
4846         }
4847     }
4848 
4849     @NonNull
getPersistableBundle(int subId)4850     private PersistableBundle getPersistableBundle(int subId) {
4851         synchronized (mCarrierConfigArrayLock) {
4852             PersistableBundle config = mCarrierConfigArray.get(subId);
4853             if (config == null) {
4854                 config = getConfigForSubId(subId);
4855                 mCarrierConfigArray.put(subId, config);
4856             }
4857             return config;
4858         }
4859     }
4860 
4861     // Should be invoked only when session termination done or session termination failed.
calculateSessionDurationTimeSec()4862     private int calculateSessionDurationTimeSec() {
4863         return (int) (
4864                 (System.currentTimeMillis() - mSessionStartTimeStamp
4865                 - mSessionMetricsStats.getSessionInitializationProcessingTimeMillis()
4866                 - mSessionMetricsStats.getSessionTerminationProcessingTimeMillis()) / 1000);
4867     }
4868 
notifyEnablementFailedToSatelliteSessionController()4869     private void notifyEnablementFailedToSatelliteSessionController() {
4870         if (mSatelliteSessionController != null) {
4871             mSatelliteSessionController.onSatelliteEnablementFailed();
4872         } else {
4873             ploge("notifyEnablementFailedToSatelliteSessionController: mSatelliteSessionController"
4874                     + " is not initialized yet");
4875         }
4876     }
4877 
getDemoPointingAlignedDurationMillisFromResources()4878     private long getDemoPointingAlignedDurationMillisFromResources() {
4879         long durationMillis = 15000L;
4880         try {
4881             durationMillis = mContext.getResources().getInteger(
4882                     R.integer.config_demo_pointing_aligned_duration_millis);
4883         } catch (Resources.NotFoundException ex) {
4884             loge("getPointingAlignedDurationMillis: ex=" + ex);
4885         }
4886 
4887         return durationMillis;
4888     }
4889 
4890     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDemoPointingAlignedDurationMillis()4891     public long getDemoPointingAlignedDurationMillis() {
4892         return mDemoPointingAlignedDurationMillis;
4893     }
4894 
getDemoPointingNotAlignedDurationMillisFromResources()4895     private long getDemoPointingNotAlignedDurationMillisFromResources() {
4896         long durationMillis = 30000L;
4897         try {
4898             durationMillis = mContext.getResources().getInteger(
4899                     R.integer.config_demo_pointing_not_aligned_duration_millis);
4900         } catch (Resources.NotFoundException ex) {
4901             loge("getPointingNotAlignedDurationMillis: ex=" + ex);
4902         }
4903 
4904         return durationMillis;
4905     }
4906 
4907     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
getDemoPointingNotAlignedDurationMillis()4908     public long getDemoPointingNotAlignedDurationMillis() {
4909         return mDemoPointingNotAlignedDurationMillis;
4910     }
4911 
getWwanIsInService(ServiceState serviceState)4912     private boolean getWwanIsInService(ServiceState serviceState) {
4913         List<NetworkRegistrationInfo> nriList = serviceState
4914                 .getNetworkRegistrationInfoListForTransportType(
4915                         AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
4916         for (NetworkRegistrationInfo nri : nriList) {
4917             if (nri.isInService()) {
4918                 logv("getWwanIsInService: return true");
4919                 return true;
4920             }
4921         }
4922 
4923         logv("getWwanIsInService: return false");
4924         return false;
4925     }
4926 
logv(@onNull String log)4927     private static void logv(@NonNull String log) {
4928         Rlog.v(TAG, log);
4929     }
4930 
logd(@onNull String log)4931     private static void logd(@NonNull String log) {
4932         Rlog.d(TAG, log);
4933     }
4934 
logw(@onNull String log)4935     private static void logw(@NonNull String log) {
4936         Rlog.w(TAG, log);
4937     }
4938 
loge(@onNull String log)4939     private static void loge(@NonNull String log) {
4940         Rlog.e(TAG, log);
4941     }
4942 
isSatellitePersistentLoggingEnabled( @onNull Context context, @NonNull FeatureFlags featureFlags)4943     private boolean isSatellitePersistentLoggingEnabled(
4944             @NonNull Context context, @NonNull FeatureFlags featureFlags) {
4945         if (featureFlags.satellitePersistentLogging()) {
4946             return true;
4947         }
4948         try {
4949             return context.getResources().getBoolean(
4950                     R.bool.config_dropboxmanager_persistent_logging_enabled);
4951         } catch (RuntimeException e) {
4952             return false;
4953         }
4954     }
4955 
plogd(@onNull String log)4956     private void plogd(@NonNull String log) {
4957         Rlog.d(TAG, log);
4958         if (mPersistentLogger != null) {
4959             mPersistentLogger.debug(TAG, log);
4960         }
4961     }
4962 
plogw(@onNull String log)4963     private void plogw(@NonNull String log) {
4964         Rlog.w(TAG, log);
4965         if (mPersistentLogger != null) {
4966             mPersistentLogger.warn(TAG, log);
4967         }
4968     }
4969 
ploge(@onNull String log)4970     private void ploge(@NonNull String log) {
4971         Rlog.e(TAG, log);
4972         if (mPersistentLogger != null) {
4973             mPersistentLogger.error(TAG, log);
4974         }
4975     }
4976 
handlePersistentLoggingOnSessionStart(RequestSatelliteEnabledArgument argument)4977     private void handlePersistentLoggingOnSessionStart(RequestSatelliteEnabledArgument argument) {
4978         if (mPersistentLogger == null) {
4979             return;
4980         }
4981         if (argument.isEmergency) {
4982             DropBoxManagerLoggerBackend.getInstance(mContext).setLoggingEnabled(true);
4983         }
4984     }
4985 
handlePersistentLoggingOnSessionEnd(boolean isEmergency)4986     private void handlePersistentLoggingOnSessionEnd(boolean isEmergency) {
4987         if (mPersistentLogger == null) {
4988             return;
4989         }
4990         DropBoxManagerLoggerBackend loggerBackend =
4991                 DropBoxManagerLoggerBackend.getInstance(mContext);
4992         // Flush persistent satellite logs on eSOS session end
4993         if (isEmergency) {
4994             loggerBackend.flushAsync();
4995         }
4996         // Also turn off persisted logging until new session is started
4997         loggerBackend.setLoggingEnabled(false);
4998     }
4999 
5000     /**
5001      * Set last emergency call time to the current time.
5002      */
setLastEmergencyCallTime()5003     public void setLastEmergencyCallTime() {
5004         synchronized (mLock) {
5005             mLastEmergencyCallTime = getElapsedRealtime();
5006             plogd("mLastEmergencyCallTime=" + mLastEmergencyCallTime);
5007         }
5008     }
5009 
5010     /**
5011      * Check if satellite is in emergency mode.
5012      */
isInEmergencyMode()5013     public boolean isInEmergencyMode() {
5014         synchronized (mLock) {
5015             if (mLastEmergencyCallTime == 0) return false;
5016 
5017             long currentTime = getElapsedRealtime();
5018             if ((currentTime - mLastEmergencyCallTime) <= mSatelliteEmergencyModeDurationMillis) {
5019                 plogd("Satellite is in emergency mode");
5020                 return true;
5021             }
5022             return false;
5023         }
5024     }
5025 
getSatelliteEmergencyModeDurationFromOverlayConfig(@onNull Context context)5026     private long getSatelliteEmergencyModeDurationFromOverlayConfig(@NonNull Context context) {
5027         Integer duration = DEFAULT_SATELLITE_EMERGENCY_MODE_DURATION_SECONDS;
5028         try {
5029             duration = context.getResources().getInteger(com.android.internal.R.integer
5030                     .config_satellite_emergency_mode_duration);
5031         } catch (Resources.NotFoundException ex) {
5032             ploge("getSatelliteEmergencyModeDurationFromOverlayConfig: got ex=" + ex);
5033         }
5034         return TimeUnit.SECONDS.toMillis(duration);
5035     }
5036 }
5037